Skip to content

Latest commit

 

History

History
431 lines (402 loc) · 15.1 KB

java-io.md

File metadata and controls

431 lines (402 loc) · 15.1 KB

Back to Home

The Overview of Java I/O

Java I/O (Input/Output) refers to the set of classes and interfaces provided by Java for reading and writing data from and to various sources such as files, network connections, and memory buffers.

Java I/O is divided into two categories: streams and readers/writers. Streams are used for handling binary data, while readers and writers are used for handling character data.

Java provides two types of streams: byte streams and character streams. Byte streams are used for handling binary data, such as images and sound files, while character streams are used for handling text data, such as files containing text.

Java provides several classes for reading and writing files, such as FileInputStream and FileOutputStream for reading and writing binary files, and FileReader and FileWriter for reading and writing text files. Here's an example of using the FileInputStream class to read a file:

try (FileInputStream inputStream = new FileInputStream("myfile.txt")) {
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = inputStream.read(buffer)) != -1) {
    // process buffer
    }
} catch (IOException e) {
    // handle exception
}

In this example, we create a FileInputStream object to read from the file myfile.txt. We then create a byte array to store the data read from the file, and read from the file into the buffer in a loop until the end of the file is reached.

Java also provides several classes for working with network connections, such as Socket and ServerSocket. Here's an example of using the Socket class to connect to a remote server:

try (Socket socket = new Socket("www.example.com", 80)) {
    OutputStream outputStream = socket.getOutputStream();
    String message = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
    outputStream.write(message.getBytes());
    outputStream.flush();
    InputStream inputStream = socket.getInputStream();
    // process response
} catch (IOException e) {
    // handle exception
}

In this example, we create a Socket object to connect to the remote server www.example.com on port 80. We then create an OutputStream to send a GET request to the server, and an InputStream to receive the response.

Finally, Java also provides several classes for working with memory buffers, such as ByteArrayInputStream and ByteArrayOutputStream. Here's an example of using the ByteArrayInputStream class to read from a byte array:

byte[] buffer = new byte[] { 1, 2, 3, 4, 5 };
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer)) {
    int b;
    while ((b = inputStream.read()) != -1) {
    // process byte
    }
} catch (IOException e) {
    // handle exception
}

In this example, we create a ByteArrayInputStream object to read from the byte array buffer. We then read from the byte array in a loop until the end of the array is reached.

I hope this gives you a good overview of Java I/O and how to use it in your programs!

Blocking I/O (BIO)

In Java, BIO stands for Blocking I/O, which is a traditional I/O model where the calling thread blocks until the I/O operation is completed. This means that when a thread calls a blocking I/O operation, it will be suspended until the operation completes, and the thread cannot do anything else while waiting for the operation to finish.

In Java, blocking I/O is implemented using streams, which are objects used to read from or write to a source. The most common stream classes for blocking I/O are InputStream and OutputStream, which are used for reading and writing bytes, respectively.

Here's an example of using a blocking I/O to read data from a file:

try (InputStream inputStream = new FileInputStream("file.txt")) {
    byte[] buffer = new byte[1024];
    int read = inputStream.read(buffer);
    while (read != -1) {
        // process data
        read = inputStream.read(buffer);
    }
} catch (IOException e) {
    // handle exception
}

In this example, we create an InputStream object to read from the file file.txt. We then create a buffer to hold the data read from the file, and read from the file into the buffer in a loop until the end of the file is reached. The read() method blocks until data is available or the end of the stream is reached.

One of the main disadvantages of blocking I/O is that it can be very slow when dealing with multiple clients. For example, if a server needs to handle multiple clients simultaneously, it may need to create a separate thread for each client, which can quickly consume system resources and make the application slow and unresponsive.

To overcome this issue, Java provides non-blocking I/O (NIO) classes, which are based on a new I/O model called asynchronous I/O (AIO). Unlike blocking I/O, AIO does not block the calling thread, but instead uses a callback mechanism to notify the application when the I/O operation is complete.

Overall, while blocking I/O may be simpler to understand and use, it is not always the most efficient solution for high-performance applications. For such applications, NIO and AIO may be a better choice.

Non-blocking I/O (NIO)

Java NIO (New I/O) is an alternative to the traditional blocking I/O model that provides a more flexible and efficient way of handling I/O operations. NIO was introduced in Java 1.4 and provides a set of classes and interfaces that allow for non-blocking I/O operations.

The key classes and interfaces in Java NIO include:

  • Channels: Channels are similar to streams, but they can be both readable and writable, and can be non-blocking. The main channel classes are FileChannel, DatagramChannel, and SocketChannel.
  • Buffers: Buffers are used to hold data for input and output operations. They can be read from or written to, and they are used in conjunction with channels to transfer data between the application and I/O devices.
  • Selectors: Selectors are used to monitor multiple channels for I/O events, such as data being ready to read or write. This allows for efficient management of multiple connections with a small number of threads.

Here's an example of using Java NIO to read data from a file:

try (RandomAccessFile file = new RandomAccessFile("file.txt", "r")) {
    FileChannel channel = file.getChannel();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int bytesRead = channel.read(buffer);
    while (bytesRead != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            // process data
            buffer.get();
        }
        buffer.clear();
        bytesRead = channel.read(buffer);
    }
} catch (IOException e) {
    // handle exception
}

In this example, we use a RandomAccessFile to open the file file.txt in read-only mode. We then get a FileChannel from the file, create a ByteBuffer to hold the data, and read data from the channel into the buffer. We then process the data in the buffer, and continue reading data from the channel until the end of the file is reached.

Java NIO also provides support for non-blocking socket I/O, which can be used to handle large numbers of connections with a small number of threads. Here's an example of using Java NIO to create a non-blocking socket:

try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
    serverSocketChannel.configureBlocking(false);
    serverSocketChannel.bind(new InetSocketAddress(8080));
    Selector selector = Selector.open();
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    while (true) {
        int readyChannels = selector.select();
        if (readyChannels == 0) {
            continue;
        }
        Set<SelectionKey> selectedKeys = selector.selectedKeys();
        Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
        while (keyIterator.hasNext()) {
            SelectionKey key = keyIterator.next();
            if (key.isAcceptable()) {
                // handle incoming connection
            } else if (key.isReadable()) {
                // handle incoming data
            } else if (key.isWritable()) {
                // handle outgoing data
            }
            keyIterator.remove();
        }
    }
} catch (IOException e) {
    // handle exception
}

In this example, we create a ServerSocketChannel and configure it to be non-blocking. We then bind the channel to port 8080 and register it with a Selector, which will monitor the channel for incoming connections. We then enter a loop that will wait for I/O events on any of the registered channels. When an event occurs, we handle it by checking the SelectionKey and performing the appropriate action.

Overall, Java NIO provides a more efficient and scalable way to handle I/O operations, especially in high-performance applications that require the management of multiple connections.

Asynchronous I/O (AIO)

Java AIO (Asynchronous I/O) is another alternative to the traditional blocking I/O model and is available in Java 7 and higher. AIO is designed to provide a non-blocking I/O model that can handle a large number of simultaneous connections and allows developers to write more scalable and responsive applications.

The key classes and interfaces in Java AIO include:

  • AsynchronousSocketChannel: This is the main class that represents a non-blocking socket channel that can be used for reading and writing data asynchronously.
  • AsynchronousServerSocketChannel: This is a class that represents a non-blocking server socket channel that can be used for accepting incoming connections.
  • CompletionHandler: This is an interface that defines callback methods that will be invoked when an I/O operation is completed.

Here's an example of using Java AIO to read data from a file:

try (AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(Paths.get("file.txt"))) {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    fileChannel.read(buffer, 0, null, new CompletionHandler<Integer, Void>() {
        @Override
        public void completed(Integer result, Void attachment) {
            buffer.flip();
            while (buffer.hasRemaining()) {
                // process data
                buffer.get();
            }
            buffer.clear();
        }
        @Override
        public void failed(Throwable exc, Void attachment) {
            // handle exception
        }
    });
} catch (IOException e) {
    // handle exception
}

In this example, we use AsynchronousFileChannel to open the file file.txt and read data from it asynchronously. We create a ByteBuffer to hold the data, and then call the read() method on the file channel, passing in the buffer, the position in the file to start reading from, and a CompletionHandler that defines the callback methods to be invoked when the read operation is completed. In the completed() method of the CompletionHandler, we process the data in the buffer, and in the failed() method, we handle any exceptions that occurred during the read operation.

Java AIO can also be used for non-blocking socket I/O, similar to Java NIO. Here's an example of using Java AIO to create a non-blocking socket:

try (AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open()) {
    serverSocketChannel.bind(new InetSocketAddress(8080));
    serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
        @Override
        public void completed(AsynchronousSocketChannel channel, Void attachment) {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            channel.read(buffer, null, new CompletionHandler<Integer, Void>() {
                @Override
                public void completed(Integer result, Void attachment) {
                    buffer.flip();
                    while (buffer.hasRemaining()) {
                        // process data
                        buffer.get();
                    }
                    buffer.clear();
                    channel.write(buffer, null, new CompletionHandler<Integer, Void>() {
                        @Override
                        public void completed(Integer result, Void attachment) {
                            // handle outgoing data
                        }
                        @Override
                        public void failed(Throwable exc, Void attachment) {
                            // handle exception
                        }
                    });
                }
                @Override
                public void failed(Throwable exc, Void attachment) {
                    // handle exception
                }
            });
        }
        @Override
        public void failed(Throwable exc, Void attachment) {
            // handle exception
        }
    });
} catch (IOException e) {
    // handle exception
}

In this example, we create an AsynchronousServerSocketChannel and bind it to port 8080. We then call the accept() method on the channel, passing in a CompletionHandler.

Java I/O FAQ

1. What is Java IO?

Java IO (Input/Output) is a set of APIs in Java that provides a way to read and write data to and from external sources such as files, network sockets, and input/output streams.

2. What are the different types of streams in Java IO?

There are two types of streams in Java IO: byte streams and character streams. Byte streams are used to read and write binary data, while character streams are used to read and write text data.

3. What is the difference between FileInputStream and FileReader?

FileInputStream is a byte stream used to read binary data from a file, while FileReader is a character stream used to read text data from a file.

4. What is a BufferedOutputStream?

A BufferedOutputStream is an OutputStream that adds buffering to an underlying output stream, which can improve performance by reducing the number of system calls needed to write data.

5. What is serialization in Java IO?

Serialization is the process of converting an object into a stream of bytes so that it can be stored in a file or transmitted over a network. Deserialization is the reverse process of converting a stream of bytes back into an object.

6. What is the purpose of the java.nio package?

The java.nio (New I/O) package provides a set of APIs for performing non-blocking I/O operations, which can improve performance and scalability of I/O-intensive applications.

7. What is a FileChannel in Java NIO?

A FileChannel is a channel that is used to read from and write to files in Java NIO. It provides methods for reading and writing data at specific positions in a file, as well as for mapping a region of a file directly into memory.

8. What is the difference between Java NIO and Java AIO?

Java NIO (New I/O) is a set of APIs for performing non-blocking I/O operations using channels and buffers, while Java AIO (Asynchronous I/O) is a set of APIs for performing asynchronous I/O operations using completion handlers. Java AIO provides a higher-level abstraction for asynchronous I/O operations, while Java NIO provides more control over the low-level details of I/O operations.