preface

In the last article to get a good number of page views, the idea of continuing to add more has been wandering in mind, originally wanted to spend some time to in-depth study of Tomcat, but tomcat source code has a vital NIO, so have to first complete NIO, but NIO is based on BIO, so this article will first write IO flow.

Learn NIO(non-blocking IO), do not block IO wow!

I/O streams are an important part of Java, but it’s easy to overlook because there’s so little code that actually writes I/O at work.

The difficulty with IO is

  1. IO stream API many, various basic streams, wrapped streams nested use is difficult to remember
  2. Basically every method throws a non-runtime exception

As a result, many developers who have learned IO streams for a period of time cannot write the correct IO stream code.

This article will take you to learn IO flow from the theory + code way, through the graphical way to memorize common IO flow.

At the end of the article, there is a mind map summarized by IO. Many blog posts use the previous one. I think it is easy for readers to get stuck in it.

File

The File class is mainly an abstract representation of files and directories. Because the first response to learning IO streams is files, this class provides operations such as creating, deleting, and searching files. The main features are as follows

  1. In Java, where everything is an object, files and directories can be abstracted as File objects
  2. In the case of File, the wrapper is not really a File, it is just a pathname, and the disk File itself may or may not exist
  3. The contents of a File cannot be read by File, but by stream. File objects can serve as the source and destination of streams

A common constructor for the File class

A constructor Method statement
File(String pathname) Abstract the path string, which can be a relative or absolute path, to a File instance
File(String parent, String child) Build File instances from parent and child pathnames
File(File parent, String child) Build a File instance based on the parent File instance and child path name

The following example shows the code for these files and directories

// pathname
File liuBei = new File("D:/ Three Kingdoms/LiuBei.jpg");
// String parent, String child
File guanYu = new File("D: / in The Three Kingdoms"."Guan yu. JPG");
/ / directory
File sanGuo = new File("D: / in The Three Kingdoms");
// File parent, String child
File zhangFei = new File(sanGuo, "Zhang fei. TXT");
// You can declare a file that does not exist
File zhuGeLiang = new File(sanGuo, "Zhuge Liang. TXT");
Copy the code

Absolute path and relative path

Absolute path: indicates a complete path starting from the drive letter. (Often used) Relative path: Path relative to the current project directory

File f = new File("D:/bbb.java");
// D:\bbb.java
System.out.println(f.getAbsolutePath());
File f2 = new File("bbb.java");
// F:\code\ad\bbb.java
System.out.println(f2.getAbsolutePath());

Copy the code

Path separator and newline character

Path separator

  1. Windows path separator: \
  2. Linux path separator: /

Java has the constant separator for the path separator

public static final String separator = "" + separatorChar;
Copy the code

A newline

  1. Windows newline: \r\n
  2. Linux newline character \n

Common methods of File

Create, delete

The method name Method statement
boolean createNewFile() throws IOException Creates an empty file with the abstract pathname and returns true if the file does not exist, or false if the file does exist
boolean mkdir() Create a directory named by this abstract pathname
boolean mkdirs() Create directories named by this abstract pathname, including any required but nonexistent parent directories. Create directories in cascades
boolean delete() Deletes the file or directory represented by this abstract pathname

The above method is relatively simple, but it needs to be noted that

  • When creating a multilevel directory, return false if mkdir fails and true if mkdirs succeeds (mkdirs is recommended).
  • If the directory is not empty, the deletion fails. False is returned, that is, only files or empty directories can be deleted
File shuiHu = new File("D:/ The Four Great Novels/outlaws of the Marsh");
// Return false creation failed
boolean mkdir = shuiHu.mkdir();
// Return true creation failed
boolean mkdirs = shuiHu.mkdirs();

File four = new File("D:/ The Four Great Classics");
// False The directory can be deleted successfully only when the directory is empty
boolean delete = four.delete();

File shuiHu = new File("D:/ The Four Great Novels/outlaws of the Marsh");
// true deletes the water Margin directory correctly
boolean delete1 = shuiHu.delete();

File liuBei = new File("D:/ Three Kingdoms/LiuBei.jpg");
// Return true the liube.jpg file was deleted correctly
boolean delete2 = liuBei.delete();
Copy the code

File detection

The method name Method statement
boolean isDirectory() Check whether it is a directory
boolean isFile() Check whether it is a file
boolean exists() Check whether a file or directory exists
boolean canWrite() Whether the file is writable
boolean canRead() Whether the file is readable
boolean canExecute() Whether the file is executable
long lastModified() Returns the last time the file was modified

Pay attention to is

  • IsDirectory () or isFile() returns false if the file or directory does not exist
  • Read, write, and execute permissions are granted to files by the operating system
File xiYou = new File(D:/ Journey to the West);
// Return false if the file or directory does not exist
System.out.println(xiYou.isDirectory());
Copy the code

File access

The method name Method statement
String getAbsolutePath() Returns the absolute path string of the File object
String getPath() Convert this abstract pathname to a pathname string
String getName() Returns the name of a file or directory
long length() Returns the number of bytes of the File represented by this File
String[] list() Returns a string array of files and directory names in a directory
File[] listFiles() Returns an array of files in a directory and a directory’s File objects

Pay attention to

  • Length () returns the number of bytes in the file, and the length of the directory is 0
  • GetPath () is the same for files represented by absolute paths, but different for files represented by relative paths
  • Calls to the listFiles and list methods must be actual directories, otherwise null is returned
  • ListFiles and list can be passed into the FilenameFilter implementation class to filter files by file name
File shuiHu = new File("D:/ water margin");
/ / 0
System.out.println(shuiHu.length());
File liuBei = new File("D:/ Three Kingdoms/LiuBei.jpg");
/ / 24591
System.out.println(liuBei.length());

File f = new File("D:/bbb.java");
 // D:\bbb.java
System.out.println(f.getPath());

File f2 = new File("bbb.java");
// bbb.java
System.out.println(f2.getPath());

File sanGuo2 = new File("D: / 2 of The Three Kingdoms");
// The directory does not exist, null is returned
String[] list = sanGuo2.list();
Copy the code

Interface for filtering files

@FunctionalInterface
public interface FilenameFilter {
  	// Take the directory and specify the filter name
    boolean accept(File dir, String name);
}
Copy the code

Extension (implemented by the reader)

Read all files and directories under a directory, including all files and directories under subdirectories

IO stream

In the previous section, you learned how to use the File class to create, find, and delete files, but not to read or transfer the contents of a File.

IO streams are used to read, transmit, and write data.

I: input, O: the output

The main body here is talking about the program (that is, memory), reading data from the external device into the program is the input stream, from the program to write to the external program is the output stream

The classification of the IO

  • Local IO and network IO

    Local I/O is used to operate local files. For example, you can copy and paste operation files on the Windows operating system using Java I/O

    Network IO is used to send data or upload or download files over the network. We experience IO transmission all the time when we surf the Internet every day

  • Divided by direction, input flow and output flow

  • Divided by data type: byte stream and character stream

  • By function: node flow and processing flow

    • Classes in which programs operate directly on target devices are called node flows
    • The node flow is decorated and enhanced in function and performance, which is called the processing flow

The main entry point of AN I/O stream is a data source. Common source and destination devices are listed below

The source device

  1. Hard disk (file)
  2. Memory (byte arrays, strings, etc.)
  3. The network (Socket)
  4. The keyboard (System.) in

Purpose equipment

  1. Hard disk (file)
  2. Memory (byte arrays, strings, etc.)
  3. The network (Socket)
  4. The console System. (out)

This article first explores byte streams and character streams of local IO, and first enumerates common methods for byte streams and character streams

The method name Method statement
void close() throws IOException After a stream operation is complete, system resources must be released and the close method called, usually ina finally block, is guaranteed to be executed!

Note:

  • The I/O resources opened in the program do not belong to memory resources and cannot be reclaimed by the garbage collection mechanism. Therefore, you need to explicitly disable file resources
  • The following code example does not explicitly call the close method and does not handle IOException, just for the sake of brevity and ease of reading

Byte stream

Everything is a byte

All file data (text, pictures, video, etc.) is stored in binary format and can be transmitted using a byte stream.

InputStream is the top-level abstraction of a byte InputStream

// Closeable has the close() method
public abstract class InputStream implements Closeable {}
Copy the code

The core approach is as follows

The method name Method statement
int read() throws IOException; Read one byte at a time, promoted to int, and return -1 at the end of the file
int read(byte b[])throws IOException Returns the number of bytes read each time a byte array is read, and -1 at the end (common)
int read(byte b[], int off, int len) Each read into the byte array, starting with offset off and length len, returns the number of valid bytes read and -1 at the end of the read

OutputStream is the top-level abstraction of a byte OutputStream

// Flushable has the flush() method
public abstract class OutputStream implements Closeable.Flushable {}
Copy the code

The core approach is as follows

The method name Method statement
void write(int b) throws IOException; Writes an int value to the output stream
void write(byte[] b) throws IOException; Writes an array of bytes to the output stream
void write(byte b[], int off, int len) throws IOException Writes the byte array to the output stream by len lengths, starting with the offset off
void flush() throws IOException Flushes the output stream and forces buffered bytes to be written out

File node flow

InputStream has a number of implementation classes. Let’s start with file node streams. The target device is a file

FileInputStream and FileOutputStream

A FileInputStream reads data from a disk file

public FileInputStream(File file) throws FileNotFoundException{}
public FileInputStream(String name) throws FileNotFoundException{};
Copy the code

The runtime throws a FileNotFoundException when the incoming file does not exist

  1. The read() method reads
File file = new File("D:/ three Kingdoms/Zhuge Liang.txt");
FileInputStream fileInputStream = new FileInputStream(file);

// Core code
int b;
while((b = fileInputStream.read()) ! = -1 ){
    System.out.print((char) b);
}

// Output the result
abcde
Copy the code
  1. Read the read (byte [])
File file = new File("D:/ three Kingdoms/Zhuge Liang.txt");
FileInputStream fileInputStream = new FileInputStream(file);

// Core code
byte[] data = new byte[2];
while(fileInputStream.read(data) ! = -1) {
    System.out.println(new String(data));
}

// Output the result
ab
cd
ed
Copy the code

Because the last time I read the above code, I only read a byte e, and the array is the same as the previous data CD, only replacing e, so I finally output Ed

Here is the correct pose read using FileInputStream

File file = new File("D:/ three Kingdoms/Zhuge Liang.txt");
FileInputStream fileInputStream = new FileInputStream(file);

// Core code
byte[] data = new byte[2];
int len;
while((len = fileInputStream.read(data)) ! = -1) {
    Len is the number of valid bytes read each time
    System.out.println(new String(data, 0, len));
}

// Output the result
ab
cd
e
Copy the code

Note: The use of array read, read multiple bytes each time, reduce the number of IO operations between systems, thus improving efficiency, recommended use

The source code parsing

public int read(a) throws IOException {
    return read0();
}
private native int read0(a) throws IOException;

public int read(byte b[]) throws IOException {
   return readBytes(b, 0, b.length);
}
private native int readBytes(byte b[], int off, int len) throws IOException;
Copy the code

The source code for read() and read(byte[]) is listed above, which can be seen as calling native methods, involving underlying system calls.

  • If you read a file with read(), the hard disk is accessed once for every byte read, which is less efficient.

  • If a file is read with read(byte[]), multiple bytes are read at a time. If the file is large, the hard disk is accessed frequently. If you read too many bytes at a time, it is not efficient.

A FileOutputStream writes data to a disk file

Constructor name Method statement
FileOutputStream(File file) throws FileNotFoundException Build a FileOutputStream using a File object
FileInputStream(String name) throws FileNotFoundException Build a FileOutputStream using a filename
FileOutputStream(File file, boolean append) throws FileNotFoundException When append passes true, the file is appended
FileOutputStream(String name, boolean append) throws FileNotFoundException When append passes true, the file is appended

Note:

  • After the above constructor is executed, the file is automatically created if it does not exist

  • If file exists and Append does not pass it or passes false, it clears the file’s data

  • If file exists, Append passes true and does not clear the file’s data

File file = new File("D:/ three Kingdoms/zhaoyun.txt");
FileOutputStream fos = new FileOutputStream(file);
FileOutputStream fos1 = new FileOutputStream("D:/ three Kingdoms/Sima Yi.txt");
TXT and sima yi.txt will be created automatically after the above code is executed
Copy the code

Write data to a file

FileOutputStream fos = new FileOutputStream("D:/ three Kingdoms/Sima Yi.txt");
fos.write(96);
fos.write(97);
fos.write(98);
// The file content is ABC

FileOutputStream fos = new FileOutputStream("D:/ three Kingdoms/zhaoyun.txt");
fos.write("Zhao Yun of The Three Kingdoms".getBytes());
// The content of the document is Zhao Yun of The Three Kingdoms
Copy the code

Each time the above code is executed, the contents of the file will be overwritten. Sometimes this is not the scenario we want, we usually want to append the file

FileOutputStream fos = new FileOutputStream("D:/ three Kingdoms/zhaoyun.txt".true);
fos.write("I have the courage to do something wrong.".getBytes());
fos.close();
// The content of the document is that Zhao Yun of The Three Kingdoms has the courage of thousands of men
Copy the code

Application scenarios

The development of files involved in the upload, download, transfer are used in this node flow, will be used together with the decorated processing flow, described in the buffer flow section.

Extension (implemented by the reader)

File node stream is used to copy files

Memory node flow

ByteArrayInputStream reads data from an array of bytes in memory

public ByteArrayInputStream(byte buf[]) {}
Copy the code

Note: There is no need to close the data source and throw IOException because no underlying system calls are involved

ByteArrayOutputStream writes data to an array of bytes in memory and maintains an array internally

public ByteArrayOutputStream(a) {
  	// A mutable byte array is maintained internally
  	// protected byte buf[];
    this(32);
}
Copy the code

Memory node flow code example

ByteArrayInputStream bis = new ByteArrayInputStream("data".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();

int len = 0;
while((len = bis.read()) ! = -1){
    bos.write(len);
}
/ / output data
System.out.println(new String(bos.toByteArray()));
Copy the code

Application scenarios

  1. The flow of in-memory operations is usually used when some temporary information is generated, and if temporary information is stored in a file, it can be troublesome to delete the file after code execution
  2. In combination with object streams, object and byte arrays can be exchanged

Characters of the flow

Character streams encapsulate methods more suitable for manipulating text characters

Reader is used to read text characters

public abstract class Reader implements Readable.Closeable {}
Copy the code

Core method

The method name Method statement
int read() throws IOException Reads a character from the input stream, returning -1 at the end of the file
int read(char cbuf[]) throws IOException Reads characters from the input stream into a char array

Writer is used to write text characters

public abstract class Writer implements Appendable.Closeable.Flushable {}
Copy the code

Core method

The method name Method statement
void write(int c) throws IOException Writes a single character to the output stream
void write(char[] cbuf) throws IOException Writes an array of characters to the output stream
void write(char[] cbuf, int off, int len) throws IOException Writes a portion of the character array, starting with offset off and length len, to the output stream
void write(String str) throws IOException Write a string directly to the output stream (common)
void write(String str, int off, int len) throws IOException Writes part of a string, starting with offsets off and length len
Writer append(char c) throws IOException Appends characters to the output stream

File node flow

Character streams are most suitable for files that operate on plain text characters, mainly FileReader and FileWriter

A FileReader writes data to a disk file

public FileReader(String fileName) throws FileNotFoundException{}
public FileReader(File file) throws FileNotFoundException {}
Copy the code

Note: A FileNotFoundException is thrown when the read file does not exist, as with FileInputStream

  1. Read () loops through the file
FileReader fileReader = new FileReader("D:/ three Kingdoms/zhaoyun.txt");
int b;
while((b = fileReader.read()) ! = -1) {
    System.out.println((char) b);
}
Copy the code
  1. Read (char[]) Reads the file
FileReader fileReader = new FileReader("D:/ three Kingdoms/zhaoyun.txt");
int len;
char[] data = new char[2];
while((len = fileReader.read(data)) ! = -1) {
    System.out.println(new String(data, 0, len));
}
// Two characters are read in sequence
Copy the code

The FileWriter constructor is similar to the FileOutStream constructor and FileOutputStream constructor.

public FileWriter(String fileName) throws IOException {}
public FileWriter(String fileName, boolean append) throws IOException {}
public FileWriter(File file) throws IOException{}
public FileWriter(File file, boolean append) throws IOException {}
Copy the code

A common method of writing data to a file

FileWriter fileWriter = new FileWriter("D:/ three Kingdoms/sunquan.txt");
fileWriter.write(97); 
fileWriter.write('b'); 
fileWriter.write('C'); 
fileWriter.write("Right"); 
fileWriter.append("Force");
Copy the code

Note:

  • If the close() or flush() methods are not performed, the data is only saved to the buffer, not to a file. This is different from FileOutputStream for the reason described in the common section of byte streams and character streams

Application scenarios

Plain text file IO operation, with the processing stream together to achieve.

Memory node flow

Character streams also have in-memory node streams, such as StringWriter and CharArrayWriter

A StringWriter writes data to an internal StringBuffer object.

/ / define
public class StringWriter extends Writer {

    private StringBuffer buf;

    public StringWriter(a) {
        buf = newStringBuffer(); lock = buf; }}/ / application
StringWriter sw = new StringWriter();
sw.write("hello");

StringBuffer buffer = sw.getBuffer();
Hello / / output
System.out.println(buffer.toString());
Copy the code

A CharArrayWriter writes data to an internal char array

/ / define
public class CharArrayWriter extends Writer {
    protected char buf[];
}

/ / application
CharArrayWriter caw = new CharArrayWriter();
caw.write("hello");
char[] chars = caw.toCharArray();
for (char c : chars) {
	// output h e L L o
	System.out.println(c);
}
Copy the code

A summary of the use of four common node flows

Common ground of byte stream and character stream

Flushable OutputStream Flushable Writer Flushable OutputStream Flushable Writer Flushable

Flush () : Forces the buffer to be flushed to the destination, after which the stream object can continue to be used

Close (): The resource is closed after the buffer is flushed forcibly. The stream object can no longer be used after the resource is closed

Buffer: can be understood as a memory area, when the program frequently operates on resources (such as files), the performance is low, because the read and write memory is fast, use the memory to buffer part of the data, do not frequently access system resources, is a way to improve efficiency

Streams that maintain buffers must be either close() or flush(), otherwise they will not be printed to the file

Processing flow

The sections above describe common node flows for byte streams and character streams, but real development uses more powerful processing flows

Processing flows are enhancements to node flows in terms of functionality and performance

The base classes for byte stream processing are FilterInputStream and FilterOutputStream

Buffer flow (emphasis)

Said in front of the node flow, are direct use of the underlying operating system method to read the data in the hard disk, the buffer flow is a kind of implementation process flow, enhance the performance of the node flow, in order to improve the efficiency, the buffer stream class at the time of initialization object, inside there is a buffer array, a one-time reading data from the underlying stream into an array, When a program executes read() or read(byte[]), it reads data directly from an in-memory array.

classification

Byte buffer stream: BufferedInputStream, BufferedOutputStream

Character buffer streams: BufferedReader, BufferedWriter

Byte buffer stream

The visible constructor passes in a node stream and decorates it

// Internal default 8192 =8*1024, that is, 8M buffer
public BufferedInputStream(InputStream in) {
  	/ / 8192
  	// The following byte array is maintained internally
    // protected volatile byte buf[];
    this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedOutputStream(OutputStream out) {
        this(out, 8192);
}
Copy the code

To feel the power of the buffering flow, use a copy of a 1-gigabyte movie

  1. Read data using basic streams (transferring one byte at a time)
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:/ Three Kingdoms/video.mp4");
FileOutputStream fos = new FileOutputStream("D:/ three kingdoms/copy.mp4");

int data;
while((data = fis.read()) ! = -1) {
    fos.write(data);
}
log.info("Copy movie time :{}ms", System.currentTimeMillis() - start);
// It is not ready in 5 minutes.
Copy the code
  1. Read data using basic streams (transferring a 8M byte array at a time)
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:/ Three Kingdoms/video.mp4");
FileOutputStream fos = new FileOutputStream("D:/ three kingdoms/copy.mp4");

int len;
byte[] data = new byte[1024 * 1024 * 1024];
while((len = fis.read(data)) ! = -1) {
    fos.write(data, 0, len);
}
log.info("Copy movie time :{}ms", System.currentTimeMillis() - start);
// Copy movie time :4651ms
Copy the code
  1. Read data using buffered streams (transferring one byte at a time)
long start = System.currentTimeMillis();
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("D:/ Three Kingdoms/video.mp4"));
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("D:/ three kingdoms/copy.mp4"));

int data;
while((data = fis.read()) ! = -1) {
    fos.write(data);
}

log.info("Copy movie time :{}ms", System.currentTimeMillis() - start);
// Copy movie time: 39,033ms
Copy the code
  1. Read data using buffered streams (transferring a 8M byte array at a time)(most often used)
long start = System.currentTimeMillis();
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("D:/ Three Kingdoms/video.mp4"));
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("D:/ three kingdoms/copy.mp4"));

int len;
byte[] data = new byte[8 * 1024];
while((len = fis.read(data)) ! = -1) {
    fos.write(data, 0, len);
}

log.info("Copy movie time :{}ms", System.currentTimeMillis() - start);
// Copy movie time :1946ms
Copy the code

From the four examples above, you can conclude that a buffered stream reads data much faster than a normal stream!

Note: the use of read and write mode, a transmission of several megabytes of data efficiency is relatively high, if the first file data are read into memory, in writing, so the number of read and write is small, but occupy too much memory space, a read too large data also seriously affect efficiency!

Character buffer stream

To decorate the character node stream, here is the constructor of the character buffer stream

public BufferedReader(Reader in) {
	// private static int defaultCharBufferSize = 8192;
	// An array of characters is maintained internally
    // private char cb[];
    this(in, defaultCharBufferSize);
}

public BufferedWriter(Writer out) {
        this(out, defaultCharBufferSize);
}
Copy the code

A unique method for character-buffering streams

class The method name Method statement
BufferedReader String readLine() throws IOException Read line by line and return NULL on the last line
BufferedWriter void newLine() throws IOException Write a line break to the file to implement a line break
// Create a stream object
BufferedReader br = new BufferedReader(new FileReader("D:/ three Kingdoms/zhaoyun.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:/ three Kingdoms/Zhao Zilong.txt"));
String line = null;
while((line = br.readLine())! =null) {
  System.out.println(line);
  bw.write(line);
  bw.newLine();
}
/ / the resultI am Zhao Zilong of Changshan, the head of a generalCopy the code

Correct posture for buffering flow

Buffer flow is the most important knowledge in IO flow, the following code to achieve the correct IO flow posture

BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
    bis = new BufferedInputStream(new FileInputStream(new File("D:/ Three Kingdoms/video.mp4")));
    bos = new BufferedOutputStream(new FileOutputStream(new File("D:/ three kingdoms/copy.mp4")));
    int len;
    // Transfer 8M files at a time. The actual test does not affect the transfer speed
    byte[] data = new byte[8 * 1024];
    while((len = bis.read(data)) ! = -1) {
        bos.write(data, 0, len); }}catch (IOException e) {
    log.error("error", e);
} finally {
  	// Finally block to close the stream to ensure that the resource must be closed
    if(bis ! =null) {
        try {
            bis.close();
        } catch (IOException e) {
            log.error("error", e); }}if(bos ! =null) {
        try {
            bos.close();
        } catch (IOException e) {
            log.error("error", e); }}}Copy the code

Transformation flows

Character encoding and character set

A character encoding

The data stored in the computer is binary, and the numbers, English, Chinese characters and so on we see on the computer are the result of binary conversion

  • To convert a character into a binary, to an encoding

  • Convert binary to characters for decoding

    Character encoding is the rule of correspondence between natural language and binary

Character set

ASCII character set, GBK character set, Unicode character set, etc., the specific introduction of each encoding is not introduced here.

IDEA, use FileReader to read text files in the project. IDEA can be set to GBK encoding, and garbled characters appear when reading the default UTF8 text file created in Windows systems.

The following example

The default character set of IDEA is UTF-8. Here change the character set to GBK

Running code and results

FileReader fileReader = new FileReader("D:/sanguo/utf8.txt");
int read;
while((read = fileReader.read()) ! = -1) {
    System.out.print((char)read);
}
/ / huan 犲 ソ
Copy the code

InputStreamReader

A subclass of Reader that reads bytes and decodes them into characters using the specified character set. The character set can be customized or the platform’s default character set can be used.

The construction is as follows

// Use the platform default character set
public InputStreamReader(InputStream in) {}
// Specify a character set
public InputStreamReader(InputStream in, String charsetName)
        throws UnsupportedEncodingException{}
Copy the code

Read “hello” from a file whose default character set is UTF8

// Create a stream object with UTF8 encoding by default
InputStreamReader isr = new InputStreamReader(new FileInputStream("D: / / utf8 kingdoms. TXT"));
// Create a stream object with GBK encoding
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("D: / / utf8 kingdoms. TXT"), "GBK");

int read;
while((read = isr.read()) ! = -1) {
    System.out.println((char) read);
}

while((read = isr2.read()) ! = -1) {
    System.out.println((char) read);
}

// Output the resultHello huan 犲ソCopy the code

OutputStreamWriter

A subclass of Writer that encodes characters into bytes using the specified character set. The character set can be customized or the platform’s default character set can be used.

The construction is as follows

// Use the platform default character set
public OutputStreamWriter(OutputStream out) {}
// Use the platform default character set
public OutputStreamWriter(OutputStream out, String charsetName)
throws UnsupportedEncodingException{}
Copy the code

The following code, write hello to the file. The character sets and file sizes of the two files are different

// Create a stream object with UTF8 encoding by default
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:/ three Kingdoms/huang Zhong.txt"));
osw.write("Hello"); // Save to 6 bytes

// Create a stream object with GBK encoding
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("D:/ three Kingdoms/machao.txt"),"GBK");
osw2.write("Hello");// Save to 4 bytes
Copy the code

Object flow

serialization

The JDK provides an object serialization mechanism that converts an object into a binary stream, which includes the data of the object, its type, and its properties. Java objects can be converted to binary streams and written to files. The file persists information about the object.

Similarly, reading information about an object from a file is a deserialization process

The object to be serialized satisfies the following conditions:

  1. The class must implement the java.io.Serializable interface.Serializable is a markup interface (without any abstract methods). Classes that do not implement this interface will not serialize or deserialize any state and will throw NotSerializableException.
  2. All attributes of the class must be serializable. If one attribute does not need to be serializable, it is decorated with the TRANSIENT keyword

ObjectOutputStream

This class implements the serialization of objects to external devices, such as hard disk files

public ObjectOutputStream(OutputStream out) throws IOException{}
Copy the code

Commonly used method

The method name Method statement
void writeObject(Object obj) throws IOException Writes out the specified object

The following code writes the User object to a file

public class User implements Serializable {
    private static final long serialVersionUID = 8289102797441171947L;

    private String name;
    private Integer age;
}
// Here is the core code for exporting the object to a file
User user = new User("D".20);
// Create a serialized stream object
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:/ three Kingdoms/machao.txt"));
// Write out the object
out.writeObject(user);
Copy the code

Note:

  1. A Serializable entity must add a serialVersionUID variable to the Serializable entity.
  2. Do not change serialVersionUID after it is generated to avoid deserialization failure. If it is changed, an InvalidClassException will be thrown

The content of the generated file is as follows

ObjectInputStream

This class deserializes the object written by ObjectOutputStream into A Java object

public ObjectInputStream(InputStream in) throws IOException 
Copy the code

Commonly used method

The method name Method statement
Object readObject() throws IOException, ClassNotFoundException Read the object
ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:/ three Kingdoms/machao.txt"));
// Force to user
User user = (User) in.readObject();
System.out.println(user);
// Output the contentUser(name= ma Chao, age=20)
Copy the code

Object and byte array conversion

Using a combination of object streams and byte array streams, Java objects and byte[] can be converted to each other

// Convert object to byte[]
public static <T> byte[] t1(T t) {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(t);
    return bos.toByteArray();
}
// Convert byte[] to an object
public static <T> T t2(byte[] data) throws IOException, ClassNotFoundException {
    ByteArrayInputStream bos = new ByteArrayInputStream(data);
    ObjectInputStream oos = new ObjectInputStream(bos);
    return (T) oos.readObject();
}
Copy the code

Pipeline flow (Understanding)

A piped stream is mainly used for communication between two threads, that is, one thread sends data to the other thread through a piped stream

Note: Threads normally communicate using wait()/notify(). Streams can also communicate and pass data

The classes used are as follows

  • PipedInputStream and PipedOutStream
  • PipedReader and PipedWriter

Use the byte stream as an example

class Sender implements Runnable {
    private PipedOutputStream pos;
    private String msg;

    public Sender(String msg) {
        this.pos = new PipedOutputStream();
        this.msg = msg;
    }

    @Override
    public void run(a) {pos. Write (MSG) getBytes ()); }public PipedOutputStream getPos(a) {
        returnpos; }}class Receiver implements Runnable {
    private PipedInputStream pis;

    public Receiver(a) {
        this.pis = new PipedInputStream();
    }


    @Override
    public void run(a) {
         byte[] data = new byte[1024];
            int len;
            while((len = pis.read(data)) ! = -1) {
                System.out.println(new String(data, 0, len));
            }
    }
}
    
Sender sender = new Sender("hello");
Receiver receiver = new Receiver();
receiver.getPis().connect(sender.getPos());
new Thread(sender).start();
new Thread(receiver).start();
// The console prints hello
Copy the code

Input and output streams (Understanding)

System.in and system. out represent the System standard input and output devices

The default input device is the keyboard, and the default output device is the console

The default device can be changed using the setIn, setOut methods of the System class

The method we often use in development to output content to the console.

System.out.println("a");
System.out.print("b");
class System{
    public final static InputStream in = null;
    public final static PrintStream out = null;
}
public PrintStream(String fileName) throws FileNotFoundException{}
Copy the code

Data flow (Understanding)

It is mainly convenient to read Java basic types and String data, DataInputStream and DataOutputStream implementation classes

DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/ three Kingdoms/zhou Yu.txt"));
dos.writeUTF("Zhou yu");
dos.writeBoolean(false);
dos.writeLong(1234567890L);

DataInputStream dis = new DataInputStream(new FileInputStream("D:/ three Kingdoms/zhou Yu.txt"));
String s = dis.readUTF();
System.out.println(s);
boolean b = dis.readBoolean();
System.out.println(b);
/ / outputZhou yufalse
Copy the code

IO stream summary

The sections above describe each flow in detail, and there are many types of visible flows, which does add to the difficulty of memorizing. But it can be sorted out by mind mapping for easy memorization.

Mapping of byte streams

Character stream mapping

Division by function

Input and output mapping

conclusion

Short – term increase plan

  1. NIO
  2. Tomcat series source code analysis

The article is long, give a big thumbs up to those who see it! Due to the author’s limited level, the article will inevitably have mistakes, welcome friends feedback correction.

If you think this article is helpful to you, please ** like, comment, forward, read, follow ** go

Your support is my biggest motivation!!