Đọc ghi file (File I/O) trong C#

File là một tập dữ liệu được lưu trữ trên ổ đĩa với tên file và đường dẫn thư mục cụ thể. Khi một file được mở để đọc hoặc ghi, nó sẽ trở thành một stream (luồng).

Luồng về cơ bản là chuỗi các byte đi qua đường truyền. Có hai luồng chính: luồng đầu vào (input stream) và luồng đầu ra (output stream).

Luồng đầu vào được sử dụng để đọc dữ liệu từ file (thao tác đọc) và luồng đầu ra được sử dụng ghi vào file (thao tác ghi).

Các lớp I/O trong C#

Namespace System.IO có các lớp khác nhau được sử dụng để thực hiện nhiều thao tác với file, chẳng hạn như tạo và xóa file, hoặc đọc và ghi vào file, đóng file, v.v.

Bảng sau đây liệt kê một số lớp thường được sử dụng trong namespace System.IO:

STT Mô tả
1 BinaryReader

Đọc dữ liệu nguyên thủy từ một luồng nhị phân.

2 BinaryWriter

Ghi dữ liệu nguyên thủy ở định dạng nhị phân.

3 BufferedStream

Một bộ lưu trữ tạm thời cho một luồng byte.

4 Directory

Giúp thao tác với các thư mục.

5 DirectoryInfo

Được sử dụng để thực hiện các thao tác trên các thư mục.

6 DriveInfo

Cung cấp thông tin về các ổ đĩa.

7 File

Giúp thao tác với các tập tin.

8 FileInfo

Được sử dụng để thực hiện các thao tác trên các tập tin.

9 FileStream

Được sử dụng để đọc và ghi vào bất kỳ vị trí nào trong một file.

10 MemoryStream

Được sử dụng để truy cập ngẫu nhiên vào luồng dữ liệu được lưu trữ trong bộ nhớ.

11 Path

Thực hiện các thao tác trên đường dẫn.

12 StreamReader

Được sử dụng để đọc các ký tự từ một luồng byte.

13 StreamWriter

Được sử dụng để ghi các ký tự cho một luồng.

14 StringReader

Được sử dụng để đọc từ bộ đệm chuỗi.

15 StringWriter

Được sử dụng để ghi vào bộ đệm chuỗi.

Lớp FileStream trong C#

Lớp FileStream trong namespace System.IO giúp đọc, ghi và đóng file. Lớp này có nguồn gốc từ lớp trừu tượng Stream.

Bạn cần tạo một đối tượng FileStream để tạo một file mới hoặc mở một file hiện có. Cú pháp khởi tạo đối tượng FileStream như sau:


FileStream <object_name> = new FileStream(<file_name>, 
    <FileMode Enumerator>,
    <FileAccess Enumerator>, 
    <FileShare Enumerator>);

Ví dụ: chúng tôi tạo một đối tượng fileStream của lớp FileStream để đọc file có tên sample.txt như được trình bày bên dưới:


FileStream fileStream = new FileStream("sample.txt", FileMode.Open, FileAccess.Read, FileShare.Read);

Bảng sau mô tả 3 tham số kiểu enum trong phương thức khởi tạo của lớp FileStream là: FileMode, FileAccess và FileShare.

STT Mô tả
1 FileMode

Enum FileMode định nghĩa các phương thức khác nhau để mở file. Các thành viên của enum FileMode là:

  • Append: Nó mở một file hiện có và đặt con trỏ ở cuối file hoặc tạo file mới nếu file không tồn tại.
  • Create: Nó tạo một file mới.
  • CreateNew: Nó chỉ định cho hệ điều hành, rằng nó sẽ tạo một file mới.
  • Open: Nó mở một tập tin hiện có.
  • OpenOrCreate: Nó chỉ định cho hệ điều hành rằng nó sẽ mở một file nếu nó tồn tại, nếu không nó sẽ tạo một file mới.
  • Truncate: Nó mở một file hiện có và cắt kích thước của nó thành 0 byte.
2 FileAccess

Enum FileAccess có các thành viên: Read, ReadWriteWrite.

3 FileShare

Enum FileShare có các thành viên sau:

  • Inheritable: Nó cho phép một xử lý file truyền thừa kế cho các tiến trình con.
  • None: Nó từ chối chia sẻ file hiện tại.
  • Read: Nó cho phép mở file để đọc.
  • ReadWrite: Nó cho phép mở file để đọc và viết.
  • Write: Nó cho phép mở file để ghi.

Ví dụ sau đây minh họa việc sử dụng lớp FileStream:


using System;
using System.IO;

namespace FileIOApplication 
{
   class Program 
   {
      static void Main(string[] args) 
      {
         using(FileStream fileStream = new FileStream("test.dat", FileMode.OpenOrCreate, FileAccess.ReadWrite))
         {
             for (int i = 1; i <= 20; i++) 
             {
                 fileStream.WriteByte((byte)i);
             }
             fileStream.Position = 0;
			 
             for (int i = 0; i <= 20; i++) 
             {
                 Console.Write(fileStream.ReadByte() + " ");
             }
         }
         Console.ReadKey();
      }
   }
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -1

Các thao tác file nâng cao trong C#

Ví dụ trước cung cấp các thao tác file đơn giản trong C#. Tuy nhiên, để sử dụng sức mạnh to lớn của các lớp System.IO trong C#, bạn cần biết các thuộc tính và phương thức thường được sử dụng của các lớp này.

STT Mô tả
1 Đọc và ghi file text

Nó liên quan đến việc đọc và ghi vào các file text (tập tin văn bản). Lớp StreamReaderStreamWriter giúp thực hiện điều này.

2 Đọc và ghi file binary

Nó liên quan đến việc đọc và ghi vào các file binary (tập tin nhị phân). Lớp BinaryReaderBinaryWriter giúp thực hiện điều này.

3 Thao tác với thư mục và file trong Windows

Nó cung cấp cho người lập trình C# khả năng duyệt và định vị các file và thư mục trong Windows.

Đọc và ghi file text trong C#

Các lớp StreamReaderStreamWriter được sử dụng để đọc và ghi dữ liệu vào các file text (tập tin văn bản). Các lớp này có nguồn gốc từ lớp trừu tượng Stream, hỗ trợ các thao tác đọc và ghi file.

Lớp StreamReader trong C#

Lớp StreamReader kế thừa từ lớp trừu tượng TextReader đại diện cho trình đọc văn bản, nó có thể đọc một chuỗi các ký tự.

Bảng sau đây mô tả một số phương thức thường được sử dụng của lớp StreamReader:

STT Mô tả
1 Close()

Nó đóng đối tượng StreamReader và luồng bên dưới và giải phóng bất kỳ tài nguyên hệ thống nào được liên kết với trình đọc.

2 Peek()

Trả về ký tự có sẵn tiếp theo nhưng không tiêu thụ nó.

3 Read()

Đọc ký tự tiếp theo từ luồng đầu vào và tiến lên vị trí ký tự một.

Ví dụ sau đây cho thấy việc đọc file text có tên là Jamaica.txt. Dưới đây là nội dung của file:

Down the way where the nights are gay
And the sun shines daily on the mountain top
I took a trip on a sailing ship
And when I reached Jamaica
I made a stop

Đây là mã chương trình đọc file Jamaica.txt:


using System;
using System.IO;

namespace FileApplication 
{
   class Program 
   {
      static void Main(string[] args) 
      {
         try 
         {
            // Create an instance of StreamReader to read from a file.
            // The using statement also closes the StreamReader.
            using (StreamReader sr = new StreamReader("c:/jamaica.txt")) 
            {
               string line;

               // Read and display lines from the file until 
               // the end of the file is reached. 
               while ((line = sr.ReadLine()) != null) 
               {
                  Console.WriteLine(line);
               }
            }
         } 
         catch (Exception e) 
         {
            // Let the user know what went wrong.
            Console.WriteLine("The file could not be read:");
            Console.WriteLine(e.Message);
         }
         Console.ReadKey();
      }
   }
}

Hãy thử đoán xem nó hiển thị gì khi bạn biên dịch và chạy chương trình.

Lớp StreamWriter trong C#

Lớp StreamWriter kế thừa từ lớp trừu tượng TextWriter đại diện cho một trình ghi file văn bản, nó có thể ghi một chuỗi các ký tự.

Bảng sau đây liệt kê các phương thức được sử dụng phổ biến nhất của lớp này:

STT Mô tả
1 Close()

Đóng đối tượng StreamWriter hiện tại và luồng bên dưới.

2 Flush()

Xóa tất cả bộ đệm cho trình ghi hiện tại và bất kỳ dữ liệu đệm nào được ghi vào luồng bên dưới.

3 Write(bool value)

Ghi một giá trị Boolean vào chuỗi văn bản hoặc luồng. (Kế thừa từ TextWriter.)

4 Write(char value)

Ghi một ký tự vào luồng.

5 Write(decimal value)

Ghi một giá trị thập phân vào chuỗi văn bản hoặc luồng.

6 Write(double value)

Ghi một giá trị dấu phẩy động (8 byte) vào chuỗi hoặc luồng văn bản.

7 Write(int value)

Ghi một số nguyên có chữ dấu (4 byte) vào chuỗi văn bản hoặc luồng.

8 Write(string value)

Ghi một chuỗi vào luồng.

9 WriteLine()

Ghi một dấu kết thúc dòng vào chuỗi văn bản hoặc luồng.

Để biết danh sách đầy đủ các phương thức, vui lòng truy cập tài liệu C# của Microsoft.

Ví dụ sau đây minh họa việc ghi dữ liệu văn bản vào một file bằng lớp StreamWriter:


using System;
using System.IO;

namespace FileApplication 
{
   class Program 
   {
      static void Main(string[] args) 
      {
         string[] names = new string[] { "Zara Ali", "Nuha Ali" };
         
         using (StreamWriter sw = new StreamWriter("names.txt")) 
         {
            foreach (string s in names) 
            {
               sw.WriteLine(s);
            }
         }
         
         // Read and show each line from the file.
         string line = "";
         using (StreamReader sr = new StreamReader("names.txt")) 
         {
            while ((line = sr.ReadLine()) != null) 
            {
               Console.WriteLine(line);
            }
         }
         Console.ReadKey();
      }
   }
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Zara Ali
Nuha Ali

Đọc và ghi file binary trong C#

Các lớp BinaryReaderBinaryWriter được sử dụng để đọc và ghi vào file binary (tập tin nhị phân) trong C#.

Lớp BinaryReader trong C#

Lớp BinaryReader được sử dụng để đọc dữ liệu nhị phân từ một file. Một đối tượng BinaryReader được tạo bằng cách truyền một đối tượng FileStream đến phương thức khởi tạo của nó.

Bảng sau đây liệt kê một số phương thức thường được sử dụng của lớp BinaryReader:

STT Mô tả
1 Close()

Nó đóng đối tượng BinaryReader và luồng bên dưới.

2 Read()

Đọc các ký tự từ luồng hiện tại và tăng vị trí hiện tại của luồng.

3 ReadBoolean()

Đọc giá trị Boolean từ luồng hiện tại và tăng vị trí hiện tại của luồng thêm một byte.

4 ReadByte()

Đọc byte tiếp theo từ luồng hiện tại và tăng vị trí hiện tại của luồng thêm một byte.

5 ReadBytes(int count)

Đọc số byte được chỉ định từ luồng hiện tại vào một mảng byte và tăng vị trí hiện tại của luồng theo số byte đó.

6 ReadChar()

Đọc ký tự tiếp theo từ luồng hiện tại và tăng vị trí hiện tại của luồng tùy theo kiểu Encoding được sử dụng và ký tự cụ thể được đọc từ luồng.

7 ReadChars(int count)

Đọc số lượng ký tự được chỉ định từ luồng hiện tại, trả về dữ liệu trong một mảng ký tự và tăng vị trí hiện tại tùy theo kiểu Encoding được sử dụng và ký tự cụ thể được đọc từ luồng.

8 ReadDouble()

Đọc giá trị dấu phẩy động (8 byte) từ luồng hiện tại và tăng vị trí hiện tại của luồng thêm 8 byte.

9 ReadInt32()

Đọc một số nguyên có dấu (4 byte) từ luồng hiện tại và tăng vị trí hiện tại của luồng thêm 4 byte.

10 ReadString()

Đọc một chuỗi từ luồng hiện tại. Chuỗi được bắt đầu với tiền tố là độ dài, kiểu Encoding dưới dạng một số nguyên 7 bit.

Lớp BinaryWriter trong C#

Lớp BinaryWriter được sử dụng để ghi dữ liệu nhị phân vào luồng. Một đối tượng BinaryWriter được tạo bằng cách truyền một đối tượng FileStream cho phương thức khởi tạo của nó.

Bảng sau đây liệt kê các phương thức thường được sử dụng của lớp BinaryWriter:

STT Mô tả
1 Close()

Nó đóng đối tượng BinaryWriter và luồng bên dưới.

2 Flush()

Xóa tất cả bộ đệm cho trình ghi hiện tại và bất kỳ dữ liệu đệm nào được ghi vào thiết bị bên dưới.

3 Seek(int offset, SeekOrigin origin)

Đặt vị trí trong luồng hiện tại.

4 Write(bool value)

Ghi giá trị Boolean 1 byte vào luồng hiện tại, với 0 đại diện cho false và 1 đại diện cho true.

5 Write(byte value)

Ghi một byte không dấu vào luồng hiện tại và tăng vị trí luồng thêm 1 byte.

6 Write(byte[] buffer)

Ghi một mảng byte vào luồng bên dưới.

7 Write(char ch)

Ghi một ký tự Unicode cho luồng hiện tại và tăng vị trí hiện tại của luồng theo Encoding được sử dụng và các ký tự cụ thể được ghi vào luồng.

8 Write(char[] chars)

Ghi một mảng ký tự cho luồng hiện tại và tăng vị trí hiện tại của luồng theo Encoding được sử dụng và các ký tự cụ thể được ghi vào luồng.

9 Write(double value)

Ghi một giá trị dấu phẩy động (8 byte) cho luồng hiện tại và tăng vị trí luồng thêm 8 byte.

10 Write(int value)

Ghi một số nguyên có dấu (4 byte) cho luồng hiện tại và tăng vị trí luồng thêm 4 byte.

11 Write(string value)

Ghi một chuỗi được bắt đầu với tiền tố là độ dài, kiểu Encoding dưới dạng một số nguyên 7 bit của luồng hiện tại và tăng vị trí hiện tại của luồng theo Encoding được sử dụng và các ký tự cụ thể được ghi vào luồng.

Để biết danh sách đầy đủ các phương thức, vui lòng truy cập tài liệu C# của Microsoft.

Ví dụ sau đây minh họa việc đọc và ghi dữ liệu nhị phân sử dụng BinaryReader và BinaryWriter trong C#:


using System;
using System.IO;

namespace BinaryFileApplication 
{
   class Program 
   {
      static void Main(string[] args) 
      {
         BinaryWriter bw;
         BinaryReader br;
         
         int i = 25;
         double d = 3.14157;
         bool b = true;
         string s = "I am happy";
         
         //writing into the file
         try 
         {
            bw = new BinaryWriter(new FileStream("mydata.dat", FileMode.Create));
            
            bw.Write(i);
            bw.Write(d);
            bw.Write(b);
            bw.Write(s);
         } 
         catch (IOException e) 
         {
            Console.WriteLine(e.Message + "\n Cannot write to file.");
            return;
         }
         finally
         {
             bw.Close();
         }
         
         //reading from the file
         try 
         {
            br = new BinaryReader(new FileStream("mydata.dat", FileMode.Open));
            
            i = br.ReadInt32();
            Console.WriteLine("Integer data: {0}", i);
            d = br.ReadDouble();
            Console.WriteLine("Double data: {0}", d);
            b = br.ReadBoolean();
            Console.WriteLine("Boolean data: {0}", b);
            s = br.ReadString();
            Console.WriteLine("String data: {0}", s);
         } 
         catch (IOException e) 
         {
            Console.WriteLine(e.Message + "\n Cannot read from file.");
            return;
         }
         finally
         {
             br.Close();
         }
         
         Console.ReadKey();
      }
   }
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Integer data: 25
Double data: 3.14157
Boolean data: True
String data: I am happy
Lưu ý: Phải giữ nguyên thứ tự khi ghi và đọc các kiểu dữ liệu vào file nhị phân sử dụng BinaryWriter và BinaryReader trong C#.

Thao tác với thư mục và file trong Windows

C# cho phép bạn làm việc với các thư mục và file trong Windows bằng cách sử dụng các lớp DirectoryInfoFileInfo.

Lớp DirectoryInfo trong C#

Lớp DirectoryInfo có nguồn gốc từ lớp FileSystemInfo. Nó có nhiều phương thức khác nhau để tạo, di chuyển và duyệt qua các thư mục và thư mục con. Lớp này không thể được thừa kế.

Sau đây là một số thuộc tính thường được sử dụng của lớp DirectoryInfo:

STT Mô tả
1 Attributes

Trả về các thuộc tính cho tập tin hoặc thư mục hiện tại.

2 CreationTime

Trả về thời gian tạo tập tin hoặc thư mục hiện tại.

3 Exists

Trả về giá trị Boolean cho biết thư mục có tồn tại hay không.

4 Extension

Trả về chuỗi đại diện cho phần mở rộng tập tin.

5 FullName

Trả về đường dẫn đầy đủ của thư mục hoặc tập tin.

6 LastAccessTime

Trả về thời gian tập tin hoặc thư mục hiện tại được truy cập lần cuối.

7 Name

Trả về tên của thư mục.

Sau đây là một số phương thức thường được sử dụng của lớp DirectoryInfo:

STT Mô tả
1 Create()

Tạo một thư mục.

2 CreateSubdirectory(string path)

Tạo thư mục con hoặc thư mục con trên đường dẫn đã chỉ định. Đường dẫn đã chỉ định có thể liên quan đến thể hiện này của lớp DirectoryInfo.

3 Delete()

Xóa thư mục nếu nó trống.

4 GetDirectories()

Trả về các thư mục con của thư mục hiện tại.

5 GetFiles()

Trả về một danh sách file từ thư mục hiện tại.

Để biết danh sách đầy đủ các thuộc tính và phương thức, vui lòng truy cập tài liệu C# của Microsoft.

Lớp FileInfo trong C#

Lớp FileInfo có nguồn gốc từ lớp FileSystemInfo. Nó có các thuộc tính và phương thức cá thể để tạo, sao chép, xóa, di chuyển và mở file giúp tạo các đối tượng FileStream. Lớp này không thể được thừa kế.

Sau đây là một số thuộc tính thường được sử dụng của lớp FileInfo:

STT Mô tả
1 Attributes

Trả về các thuộc tính cho file hiện tại.

2 CreationTime

Trả về thời gian tạo file.

3 Directory

Trả về một thể hiện của thư mục mà file thuộc về.

4 Exists

Trả về giá trị Boolean cho biết liệu file có tồn tại hay không.

5 Extension

Trả về chuỗi đại diện cho phần mở rộng file.

6 FullName

Trả về đường dẫn đầy đủ của file.

7 LastAccessTime

Trả về thời gian lần cuối truy cập file.

8 LastWriteTime

Trả về thời gian lần cuối ghi file.

9 Length

Trả về kích thước tính bằng byte của file hiện tại.

10 Name

Trả về tên của file.

Sau đây là một số phương thức thường được sử dụng của lớp FileInfo:

STT Mô tả
1 AppendText()

Tạo một StreamWriter nối thêm văn bản vào file.

2 Create()

Tạo một file.

3 Delete()

Xóa một file vĩnh viễn.

4 MoveTo(string destFileName)

Di chuyển một file đã chỉ định đến một vị trí mới, cung cấp tùy chọn chỉ định tên file mới.

5 Open(FileMode mode)

Mở một file theo cấu hình được chỉ định.

6 Open(FileMode mode, FileAccess access)

Mở một file theo các cấu hình được chỉ định.

7 Open(FileMode mode, FileAccess access, FileShare share)

Mở một file theo các cấu hình được chỉ định.

8 OpenRead()

Tạo một FileStream chỉ đọc

9 OpenWrite()

Tạo một FileStream chỉ ghi.

Để biết danh sách đầy đủ các thuộc tính và phương thức, vui lòng truy cập tài liệu C# của Microsoft.

Ví dụ sau đây minh họa việc sử dụng các lớp được đề cập ở trên:

using System;
using System.IO;

namespace WindowsFileApplication 
{
   class Program 
   {
      static void Main(string[] args) 
      {
         //creating a DirectoryInfo object
         DirectoryInfo mydir = new DirectoryInfo(@"c:\Windows");
         
         // getting the files in the directory, their names and size
         FileInfo [] files = mydir.GetFiles();
         foreach (FileInfo file in files) 
         {
            Console.WriteLine("File Name: {0} Size: {1}", file.Name, file.Length);
         }
         
         Console.ReadKey();
      }
   }
}


Bài viết liên quan:

Reflection trong C#

  • 6 min read

Reflection trong C# là gì? Ứng dụng của Reflection trong C#. Cách khai báo và sử dụng Reflection trong C#.

Attribute trong C#

  • 7 min read

Attribute trong C# là gì? Có những loại attribute nào trong C#? Làm sao để sử dụng attribute trong C#.

Các tính năng mới của C# 8.0 được Microsoft phát hành cùng với .NET Framework 4.8 và Visual Studio 2019.