C # Basic Knowledge Series-14 IO Introduction to IO

Posted May 27, 20206 min read

0 . Foreword

In the previous chapters, some basic concepts in C # were briefly introduced. In this article, we will introduce the I/O operation of C #, which will also be a small series. This is the first episode, let's take a brief look at the I/O framework in C #.

1 . What is I/O

The full name of I/O is input/output, which translates to input/output. For a system or computer, the keyboard, U disk, network interface, display, audio, camera, etc. are all IO devices. So, what is I/O for a program?

For programs, I/O is the way to exchange data with the outside world. To borrow a slogan, the program does not produce data, it is just a laborer of data. Of course, just as XX also needs to filter, disinfect and other processes of water, the program also needs to calculate the data, so it is not completely considered as a laborer, strictly speaking, a processing plant. Then, I/O is the factory's raw material supplier and finished product seller.

In C #, the overall I/O system is divided into three parts, the background storage stream, the decorator stream, and the stream adapter, as shown in the following figure:


Between streams and streams, byte data is used for exchange, so you can get a simple conclusion. I/O appears as a stream of bytes in the program. In other words, I/O is to convert various data into words. Tools.

3 . Stream base class

In C #, all streams are inherited from the Stream class. The Stream class defines the behavior and attributes that the stream should have, so that developers can ignore the specific details of the underlying operating system and basic equipment. C # ignores the difference between read stream and write stream in stream processing, making it more like a pipe, which is convenient for data communication. The flow involves three basic operations:

  • Read-transfer data from the stream to the data structure
  • Write-write data from the data source to the stream
  • Find-Find and modify the current position of the operation in the stream

Because of the characteristics of streams, not all streams may support these three operations, so Stream provides three properties to facilitate confirmation whether the stream supports these three operations:

public abstract bool CanRead {get;} //Get the value indicating whether the current stream supports reading
public abstract bool CanWrite {get;} //Get the value indicating whether the current stream supports write function
public abstract bool CanSeek {get;} //Get the value indicating whether the current stream supports the search function

The above three attributes are all confirmed by the subclasses according to their own characteristics to support reading, writing, and searching. It is possible that all three attributes will not be true, but definitely not all will be false.

Here are some common flows:

  • FileStream is used to manipulate the stream of files
  • MemoryStream operation memory stream
  • BufferedStream buffered stream, used to enhance the operational performance of other streams
  • NetworkStream uses network sockets to operate streams
  • PipeStream reads and writes through anonymous and named pipes
  • CryptoStream is used to link the data stream to the encryption conversion

4 . Operation

I/O operations in C # all belong to the namespace System.IO. In this namespace, C # defines file-related classes, various streams, decorator streams, adapters, and other related structures. In the namespace beginning with System.IO, C # further expands IO and provides stream compression and decompression( System.IO.Compression), searching and enumerating file system elements(System.IO.Enumeration ), Provide content for using memory mapped files( System.IO.MemoryMappedFiles) and other content.

Let s skip the content that will be introduced later, let s take a look at the important properties and methods in the Stream class:

1 . Length of data in stream

public abstract long Length {get;}

When CanSeek of the Stream object is true, that is, when the stream supports search, you can use this property to confirm the length of the stream, that is, how many bytes of data.

2 . Stream location

public abstract long Position {get; set;}

The prerequisites for the same length are the same. When the Stream object supports searching, you can use this property to confirm the stream position or modify the stream position.

3 . Read the data in the stream

public abstract int Read(byte []buffer, int offset, int count);
public virtual int ReadByte();

These are two different reading methods, the first is to read multiple bytes of data at a time, and the second is to read only one byte of data at a time. Here to explain the difference in detail:

public abstract int Read(byte []buffer, int offset, int count);

Indicates that the stream reads up to count bytes of data at a time, and then puts the data in the buffer, starting at the offset index, and returns the number of bytes actually read. If the stream has been read, it returns 0. During this process, Position will shift back the actual read length. If the stream supports searching, this property can be called in the program.

So there is such a limit here:offset + count <= buffer.Length, in other words, the offset + the maximum number of reads cannot be greater than the length of the cache array.

Because this method returns an actual read length, some people may judge whether it has finished reading according to the ratio of the returned result to count. If the returned length is less than count, the stream has been read; otherwise, the stream has not been read.

Some streams may achieve this effect, but many streams cannot use this as a basis to determine whether the stream has been read. Perhaps the length of a certain read is less than count, and then read again to find that there is data. This is because IO is a time-consuming operation in the system. In most cases, the performance of IO is very different from the operation speed of the program. So often there is such a situation:the length of the stream is 100, a buffer byte array of length 100 is given, and then the first read 10 bytes, the second time read 5 bytes, such a Read these 100 bytes bit by bit.

Therefore, the return value must be 0 as the basis for judging the end of the stream.

public virtual int ReadByte();

This method is very simple, one byte of data is read from the stream at a time, and -1 is returned if the reading is completed. Some people may wonder, this method is to read a byte, that is, a byte, so why is the return type int? It's simple, because byte doesn't have negative numbers, but int does. Therefore, when the return value is not equal to -1, you can safely convert the type to byte.

4 . Write data to stream

public abstract void Write(byte []buffer, int offset, int count);
public virtual void WriteByte(byte value);

Stream writing is much simpler than reading, at least we don't need to judge the position of the stream. Now briefly analyze:

public abstract void Write(byte []buffer, int offset, int count);

Indicates that starting from the offset index of the buffer, count bytes are written to the stream. Therefore, the restrictions on offset and count are still the same, and the sum cannot be greater than the length of the array. If the writing is successful, the position of the stream will move, otherwise the existing position will be maintained.

public virtual void WriteByte(byte value);

This method is even simpler, write a byte directly to the stream.

5 . Close or destroy stream

After the operation of the stream is completed, it needs to be closed to release resources such as files or IO devices held by the stream. Many people cannot use QQ to send an excel file that has been opened locally when using a computer. It will prompt that the file is occupied and cannot be transferred. This is because Excel opens the file and holds a file-related stream, so QQ cannot send it. The solution is simple, just turn off the excel software. Back to the current, that is, we must close the stream after the use is complete.

So how do we close the stream? Call the following method:

public virtual void Close();

Although C # sets the Close method, it does not support developers to manually call the Close method when writing programs. It is more recommended to use:

public void Dispose();

This method will release the resources used by the stream and close the stream.

One thing to pay attention to now is to push the data in the stream to the basic device before closing or releasing the stream, that is, to call:

public abstract void Flush();

Some streams have an automatic push function. If you encounter such a stream, you do not need to call this method manually.

For the stream, once destroyed or closed, the stream cannot be used again, so after calling Close and Dispose, it will report an error when trying to read/write the stream again.

5 . This summary and the next trailer

This article roughly introduces the C # IO system and some basic operations. The next article will introduce how to operate the file.

For more content, please pay attention to My Blog "Mr. Gao's Cabin"