Раздел «Технологии программирования».WorkingWithIOModule:

Работа с потоками ввода-вывода


Summary

There are network, memory, and tape streams. Class Stream unifies methods for working with various kinds of IO. This section describes main principles and techniques lying behind working with IO in .NET Framework.

A file is an ordered and named collection of a particular sequence of bytes having persistent storage. Therefore, with files, one thinks in terms of directory paths, disk storage, and file and directory names. In contrast, streams provide a way to write and read bytes to and from a backing store that can be one of several storage mediums. Just as there are several backing stores other than disks, there are several kinds of streams other than file streams.

Обзор классов, нужных для работы с потоками

The abstract base class Stream supports reading and writing bytes. Stream integrates asynchronous support. Its default implementations define synchronous reads and writes in terms of their corresponding asynchronous methods, and vice versa.

All classes that represent streams inherit from the Stream class. The Stream class and its derived classes provide a generic view of data sources and repositories, isolating the programmer from the specific details of the operating system and underlying devices.

Streams involve these fundamental operations:

Depending on the underlying data source or repository, streams might support only some of these capabilities. For example, NetworkStreams do not support seeking. The CanRead, CanWrite, and CanSeek properties of Stream and its derived classes determine the operations that various streams support.

Классы, используемые для ввода-вывода

FileObject provides a representation of a text file. Use the FileObject class to perform most typical text file operations such as reading, writing, appending, copying, deleting, moving, or renaming. You can also use FileObject to examine and, in some cases, set file attributes, encoding, and path information.

Directory provides static methods for creating, moving, and enumerating through directories and subdirectories. The DirectoryInfo class provides instance methods.

DirectoryInfo provides instance methods for creating, moving, and enumerating through directories and subdirectories. The Directory class provides static methods.

File provides static methods for the creation, copying, deletion, moving, and opening of files, and aids in the creation of a FileStream. The FileInfo class provides instance methods.

FileInfo provides instance methods for the creation, copying, deletion, moving, and opening of files, and aids in the creation of a FileStream. The File class provides static methods.

FileStream supports random access to files through its Seek method. FileStream opens files synchronously by default, but supports asynchronous operation as well. File contains static methods, and FileInfo contains instance methods.

FileSystemInfo is the abstract base class for FileInfo and DirectoryInfo.

Path provides methods and properties for processing directory strings in a cross-platform manner.

File, FileInfo, Path, Directory, and DirectoryInfo are sealed classes. You can create new instances of these classes, but they cannot have derived classes.

Классы, используемые для чтения/записи в потоки

BinaryReader (BinaryWriter) reads (writes) encoded strings and primitive data types from (to) Streams.

StreamReader (StreamWriter) reads (writes) characters from Streams, using Encoding to convert characters to (from) bytes. StreamReader (StreamWriter) has a constructor that attempts to ascertain what the correct Encoding for a given Stream is, based on the presence of an Encoding-specific preamble, such as a byte order mark.

StringReader (StringWriter) reads (writes) characters from/to Strings. These classes allows you to treat Strings with the same API, so your output (input) can be either a Stream in any encoding or a String.

TextReader (TextWriter) is the abstract base classes for StreamReader and StringReader (StreamWriter and StringWriter). While the implementations of the abstract Stream class are designed for byte input and output, the implementations of TextReader=(=TextWriter) are designed for Unicode character output.

Общие классы потоков ввода-вывода

A BufferedStream is a Stream that adds buffering to another Stream such as a NetworkStream. (FileStream already has buffering internally, and a MemoryStream does not need buffering.) A BufferedStream can be composed around some types of streams in order to improve read and write performance. A buffer is a block of bytes in memory used to cache data, thereby reducing the number of calls to the operating system.

A CryptoStream links data streams to cryptographic transformations. Although CryptoStream derives from Stream, it is not part of the System.IO namespace, but is in the System.Security.Cryptography namespace.

A MemoryStream is a nonbuffered stream whose encapsulated data is directly accessible in memory. This stream has no backing store and might be useful as a temporary buffer.

A NetworkStream represents a Stream over a network connection. Although NetworkStream derives from Stream, it is not part of the System.IO namespace, but is in the System.Net.Sockets namespace.

Примеры работы с файлами/директориями

Запись/чтение текстового файла

using System;
using System.IO;
class MyStream 
{
    private const string FILE_NAME = "Test.data";
    public static void Main(String[] args) 
    {
        // Create the new, empty data file.
        if (File.Exists(FILE_NAME)) 
        {
            Console.WriteLine("{0} already exists!", FILE_NAME);
            return;
        }
        FileStream fs = new FileStream(FILE_NAME, FileMode.CreateNew);
        // Create the writer for data.
        BinaryWriter w = new BinaryWriter(fs);
        // Write data to Test.data.
        for (int i = 0; i < 11; i++) 
        {
            w.Write( (int) i);
        }
        w.Close();
        fs.Close();
        // Create the reader for data.
        fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read);
        BinaryReader r = new BinaryReader(fs);
        // Read data from Test.data.
        for (int i = 0; i < 11; i++) 
        {
            Console.WriteLine(r.ReadInt32());
        }
        w.Close();
    }
}

Добавление сообщений в лог-файл

using System;
using System.IO;
class DirAppend
{
    public static void Main(String[] args)
    {
        StreamWriter w = File.AppendText("log.txt");
        Log ("Test1", w);
        Log ("Test2", w);
        // Close the writer and underlying file.
        w.Close();
        // Open and read the file.
        StreamReader r = File.OpenText("log.txt");
        DumpLog (r);
    }
    public static void Log (String logMessage, TextWriter w)
    {
        w.Write("\r\nLog Entry : ");
        w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
            DateTime.Now.ToLongDateString());
        w.WriteLine("  :");
        w.WriteLine("  :{0}", logMessage);
        w.WriteLine ("-------------------------------");
        // Update the underlying file.
        w.Flush(); 
    }
    public static void DumpLog (StreamReader r)
    {
        // While not at the end of the file, read and write lines.
        String line;
        while ((line=r.ReadLine())!=null)
        {
            Console.WriteLine(line);
        }
        r.Close();
    }
}

Листинг директории

using System;
using System.IO;
class DirectoryLister
{
    public static void Main(String[] args)
    {
        DirectoryInfo dir = new DirectoryInfo(".");
        foreach (FileInfo f in dir.GetFiles("*.cs")) 
        {
            String name = f.FullName;
            long size = f.Length;
            DateTime creationTime = f.CreationTime;
            Console.WriteLine("{0,-12:N0} {1,-20:g} {2}", size, 
                creationTime, name);
        }
    }
}

Чтение символов из строки

using System;
using System.IO;
public class CharsFromStr
{
    public static void Main(String[] args)
    {
        // Create a string to read characters from.
        String str = "Some number of characters";
        // Size the array to hold all the characters of the string
        // so that they are all accessible.
        char[] b = new char[24];
        // Create an instance of StringReader and attach it to the string.
        StringReader sr = new StringReader(str);
        // Read 13 characters from the array that holds the string, starting
        // from the first array member.
        sr.Read(b, 0, 13);
        // Display the output.
        Console.WriteLine(b);
        // Close the StringReader.
        sr.Close();
    }
}

Копирование/перемещение файла

Для копирования файла можно использовать статический метод File.Copy. Для перемещения используется метод File.Move. Оба метода не работают при необходимости пересекать границу раздела тома.

Асинхронные операции ввода-вывода

Synchronous I/O means that the method is blocked until the I/O operation is complete, and then the method returns its data. With asynchronous I/O, a user can call BeginRead or BeginWrite. The main thread can continue doing other work, and later the user will be able to process the data. Also, multiple I/O requests can be pending simultaneously.

To be informed when this data is available, you can call EndRead or EndWrite, passing in the IAsyncResult corresponding to the I/O request you issued. You can also provide a callback method that should call EndRead or EndWrite to figure out how many bytes were read or written. Asynchronous I/O can offer better performance when many I/O requests are pending simultaneously, but generally requires some significant restructuring of your application to work correctly.

See also:

Links

-- AndreyUstyuzhanin - 07 Apr 2004