C# - C Sharp: I/O File
Tổng quan về I/O File
File (Tệp - Tập tin) là tập hợp dữ liệu (các byte) được lưu trữ trong thiết bị lưu trữ thứ cấp (secondary). Tệp có tên và có địa chỉ cụ thể.
Tệp có thể được sử dụng làm bộ nhớ phụ để lưu trữ một lượng lớn dữ liệu tạm thời hoặc vĩnh viễn. Mỗi tệp kết thúc bằng ký tự đánh dấu kết thúc hoặc một số byte.
Khi một tệp được mở để đọc hoặc ghi, nó sẽ trở thành một Stream.
Stream về cơ bản là chuỗi các byte truyền qua đường dẫn truyền thông. Có hai stream chính: input stream và output stream. Input stream được sử dụng để đọc dữ liệu từ file (thao tác đọc - read) và output stream được sử dụng để ghi vào file (thao tác ghi - write).
Namespace System.IO
Namespace System.IO có nhiều lớp khác nhau được sử dụng để thực hiện nhiều thao tác với tệp, chẳng hạn như tạo và xóa tệp, đọc hoặc ghi vào tệp, đóng tệp, v.v.
Bảng sau đây cho thấy một số lớp không trừu tượng (non-abstract) thường được sử dụng trong namespace System.IO:
STT | Lớp I/O & Mô tả |
---|---|
1 |
BinaryReader Đọc dữ liệu nguyên thủy từ một binary stream. |
2 |
BinaryWriter Ghi dữ liệu nguyên thủy ở định dạng nhị phân. |
3 |
BufferedStream Bộ lưu trữ tạm thời cho một byte stream. |
4 |
Giúp thao tác cấu trúc thư mục. |
5 |
Được sử dụng để thực hiện các hoạt động trên các thư mục. |
6 |
DriveInfo Cung cấp thông tin cho các ổ đĩa. |
7 |
Giúp thao tác với các tập tin. |
8 |
Được sử dụng để thực hiện các hoạt động trên các tập tin. |
9 |
Được sử dụng để đọc và ghi vào bất kỳ vị trí nào trong tệp. |
10 |
MemoryStream Được sử dụng để truy cập ngẫu nhiên vào dữ liệu truyền trực tuyến được lưu trữ trong bộ nhớ. |
11 |
Path Thực hiện các hoạt động trên thông tin đường dẫn. |
12 |
Được sử dụng để đọc các ký tự từ một byte stream. |
13 |
Được sử dụng để ghi các ký tự vào một stream. |
14 |
StringReader Được sử dụng để đọc từ bộ đệm chuỗi (string buffter). |
15 |
StringWriter Được sử dụng để ghi vào bộ đệm chuỗi. |
16 |
FileSystemWatcher Được sử dụng để giám sát việc sửa đổi các tệp bên ngoài trong một thư mục được chỉ định |
Làm việc với lớp FileStream
Lớp FileStream trong namespace System.IO giúp đọc, ghi và đóng tệp. FileStream cũng hỗ trợ các hoạt động đọc/ghi file đồng bộ và bất đồng bộ. Lớp này bắt nguồn từ lớp trừu tượng Stream.
Bạn cần tạo đối tượng FileStream để tạo tệp mới hoặc mở tệp hiện có. Cú pháp để tạo một đối tượng FileStream như sau:
FileStream <object_name> = new FileStream( <file_name>, <FileMode Enumerator>, <FileAccess Enumerator>, <FileShare Enumerator>);
Ví dụ: ta tạo một đối tượng FileStream có tên FS để đọc tệp có tên demo.txt như sau:
FileStream FS = new FileStream("demo.txt", FileMode.Open, FileAccess.Read, FileShare.Read);
Bảng dưới đây mô tả chi tiết hơn về FileMode, FileAccess, và FileShare.
STT | Trình liệt kê (Enumerator) và mô tả |
---|---|
1 |
FileMode Trình liệt kê FileMode định nghĩa các phương thức khác nhau để mở tệp. Các chế độ (mode) của FileMode enumerator là:
|
2 |
FileAccess FileAccess có các chế độ: Read , ReadWrite và Write. |
3 |
FileShare FileShare có các chế độ sau:
|
Ví dụ với lớp FileStream
Ví dụ 1: Ví dụ này minh họa việc sử dụng chế độ mở file hoặc tạo file (của FileMode) để đọc/ghi (của FileAccess):
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { FileStream FS = new FileStream("demo_filestream.dat", FileMode.OpenOrCreate, FileAccess.ReadWrite); for (int i = 1; i <= 20; i++) { FS.WriteByte((byte)i); } FS.Position = 0; for (int i = 0; i <= 20; i++) { Console.Write(FS.ReadByte() + " "); } FS.Close(); } } }
Kết quả:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -1
Ví dụ 2: Ví dụ này tạo một file có tên myfile.txt, file này sẽ chứa mã hóa dạng byte các ký tự của của chuỗi "V1Study"; sau đó ta đọc các byte từ file rồi giải mã thành chuỗi và hiển thị.
using System.Text; namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { //Tạo file using FileStream FS = File.Open("myfile.txt", FileMode.Create); //mã hóa một chuỗi thành một mảng các byte string s = "V1Study"; byte[] buffer = Encoding.Default.GetBytes(s); //ghi mảng buffer ra file FS.Write(buffer, 0, buffer.Length); //đặt vị trí của stream về đầu file FS.Position = 0; //đọc các byte từ file rồi hiển thị: Console.WriteLine("Mang cac byte doc duoc:"); byte[] bytes = new byte[buffer.Length]; for (int i = 0; i < buffer.Length; i++) { bytes[i] = (byte)FS.ReadByte(); Console.Write($"{bytes[i]}{(i == buffer.Length - 1 ? "" : ", ")}"); } //hiển thị chuỗi đã được giải mã: string decodeMsg = Encoding.Default.GetString(bytes); Console.WriteLine("\nGiai ma cac byte:"); Console.WriteLine(decodeMsg); FS.Close(); } } }
Làm việc với lớp File
File là một lớp tĩnh để đọc/ghi từ tập tin vật lý với ít mã hóa hơn. Lớp File cung cấp các chức năng như tạo, đọc/ghi, sao chép, di chuyển, xóa và các chức năng khác cho các tệp vật lý.
Lớp File bao gồm nhiều phương thức tiện ích khác nhau để tương tác với tệp vật lý thuộc bất kỳ loại nào như nhị phân, văn bản, v.v. Ta sử dụng lớp File này để thực hiện một số thao tác nhanh trên tệp vật lý.
Dưới đây là bảng chứa một số phương thức quan trọng của lớp File:
Phương thức |
Mô tả |
---|---|
AppendAllLines |
Nối các dòng vào tệp, rồi đóng tệp. Nếu tệp được chỉ định không tồn tại, phương thức này sẽ tạo một tệp, ghi các dòng được chỉ định vào tệp và sau đó đóng tệp. |
AppendAllText |
Mở tệp, nối thêm chuỗi đã chỉ định vào tệp, rồi đóng tệp. Nếu tệp không tồn tại, phương thức này sẽ tạo một tệp, ghi chuỗi đã chỉ định vào tệp, sau đó đóng tệp. |
AppendText |
Tạo một StreamWriter nối thêm văn bản được mã hóa dạng UTF-8 vào một tệp hiện có hoặc vào một tệp mới nếu tệp được chỉ định không tồn tại. |
Copy |
Sao chép một tệp hiện có sang một tệp mới. Ghi đè lên một tập tin cùng tên không được phép. |
Create |
Tạo hoặc ghi đè lên một tệp trong đường dẫn đã chỉ định. |
CreateText |
Tạo hoặc mở tệp để viết văn bản được mã hóa dạng UTF-8. |
Delete | Xóa file được chỉ định. |
Decrypt | Giải mã một tệp đã được mã hóa bởi tài khoản hiện tại bằng phương thức Encrypt. |
Encrypt | Mã hóa tệp để chỉ tài khoản được sử dụng để mã hóa tệp mới có thể giải mã tệp đó. |
Exists | Kiểm tra xem tệp được chỉ định có tồn tại không. |
GetAccessControl | Nhận một đối tượng FileSecurity gói gọn các mục trong danh sách kiểm soát truy cập (Access Control List - ACL) cho một tệp đã chỉ định. |
Move | Di chuyển một tệp đã chỉ định đến một vị trí mới, cung cấp tùy chọn chỉ định tên tệp mới. |
Open | Mở FileStream trên đường dẫn đã chỉ định với quyền truy cập đọc/ghi. |
ReadAllBytes | Mở tệp nhị phân, đọc nội dung của tệp thành một mảng byte, rồi đóng tệp. |
ReadAllLines | Mở tệp văn bản, đọc tất cả các dòng của tệp rồi đóng tệp. |
ReadAllText | Mở tệp văn bản, đọc tất cả các dòng của tệp rồi đóng tệp. |
Replace | Thay thế nội dung của một tệp được chỉ định bằng nội dung của một tệp khác, xóa tệp gốc và tạo bản sao lưu của tệp được thay thế. |
WriteAllBytes | Tạo một tệp mới, ghi mảng byte đã chỉ định vào tệp, sau đó đóng tệp. Nếu tệp đích đã tồn tại, nó sẽ bị ghi đè. |
WriteAllLines | Tạo một tệp mới, ghi một tập hợp các chuỗi vào tệp, sau đó đóng tệp. |
WriteAllText | Tạo một tệp mới, ghi chuỗi đã chỉ định vào tệp, sau đó đóng tệp. Nếu tệp đích đã tồn tại, nó sẽ bị ghi đè. |
Ví dụ về lớp File
Ví dụ 1: Ví dụ này sẽ tạo 1 file - sử dụng phương thức Exists() của lớp File để kiểm tra xem có tồn tại file không - rồi ghi từng dòng chuỗi vào file đó thông qua việc sử dụng StreamWriter; sau đó dùng StreamReader để đọc từng dòng chuỗi và hiển thị.
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { string file = "myfile.txt"; if (!File.Exists(file)) { //tạo 1 file để ghi dữ liệu using StreamWriter sw = new StreamWriter(file); sw.WriteLine("V1"); sw.WriteLine("Study"); } //mở file để đọc using StreamReader sr = new StreamReader(file); string s; while ((s = sr.ReadLine()) != null) { Console.WriteLine(s); } } } }
Kết quả:
V1 Study
Ví dụ 2: Ví dụ này sử dụng WriteAllText và AppendAllText của File để ghi dữ liệu vào file; sau đó sử dụng ReadAllText để đọc và hiển thị dữ liệu.
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { string file = "mydata.txt"; if (!File.Exists(file)) { //tạo file để ghi dữ liệu string writeText = "V1Study" + Environment.NewLine; File.WriteAllText(file, writeText); } string appendText = "This is extra text" + Environment.NewLine; File.AppendAllText(file, appendText); //mở file để đọc string readText = File.ReadAllText(file); Console.WriteLine(readText); } } }
Kết quả:
V1Study This is extra text
Làm việc với lớp FileInfo
Lớp FileInfo cung cấp chức năng giống như lớp File nhưng chúng ta có nhiều quyền kiểm soát hơn đối với các thao tác đọc/ghi trên tệp bằng cách viết mã thủ công để đọc hoặc ghi byte từ tệp.
Các thuộc tính quan trọng của lớp FileInfo
Thuộc tính |
Mô tả |
---|---|
Directory |
Lấy một thể hiện của thư mục cha. |
DirectoryName |
Nhận một chuỗi đại diện cho đường dẫn đầy đủ của thư mục. |
Exists |
Nhận giá trị cho biết tệp có tồn tại hay không. |
Extension | Nhận chuỗi đại diện cho phần mở rộng của tệp. |
FullName | Nhận đường dẫn đầy đủ của thư mục hoặc tệp. |
IsReadOnly | Nhận hoặc đặt giá trị xác định xem tệp hiện tại có ở chế độ chỉ đọc hay không. |
LastAccessTime | Nhận hoặc đặt thời gian tệp hoặc thư mục hiện tại được truy cập lần cuối. |
LastWriteTime | Nhận hoặc đặt thời gian khi tệp hoặc thư mục hiện tại được ghi lần cuối vào. |
Length | Lấy kích thước tính bằng byte của tệp hiện tại. |
Name | Lấy tên của tập tin |
Các phương thức quan trọng của lớp FileInfo
Phương thức |
Mô tả |
---|---|
AppendText |
Tạo một StreamWriter nối thêm văn bản vào tệp được đại diện bởi phiên bản FileInfo này. |
CopyTo |
Sao chép tệp hiện có sang tệp mới, không cho phép ghi đè lên tệp hiện có. |
Create |
Tạo một file. |
CreateText |
Tạo một StreamWriter ghi một tệp văn bản mới. |
Decrypt |
Giải mã một tệp đã được mã hóa bởi tài khoản hiện tại bằng phương thức Encrypt |
Delete |
Xóa file đã chỉ định. |
Encrypt |
Mã hóa tệp để chỉ tài khoản được sử dụng để mã hóa tệp mới có thể giải mã tệp đó. |
GetAccessControl |
Nhận một đối tượng FileSecurity gói gọn các mục trong danh sách kiểm soát truy cập (Access Control List - ACL) cho một tệp đã chỉ định. |
MoveTo | Di chuyển một tệp đã chỉ định đến một vị trí mới, cung cấp tùy chọn chỉ định tên tệp mới. |
Open | Mở một file trong FileMode được chỉ định. |
OpenRead | Tạo một FileStream chỉ đọc. |
OpenText | Tạo StreamReader với mã hóa UTF8 đọc từ tệp văn bản hiện có. |
OpenWrite | Tạo FileStream chỉ ghi |
Replace | Thay thế nội dung của một tệp đã chỉ định bằng tệp được mô tả bởi đối tượng FileInfo hiện tại, xóa tệp gốc và tạo bản sao lưu của tệp được thay thế |
ToString | Trả về chuỗi đường dẫn (path). |
Ví dụ về lớp FileInfo
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("*** Demo FileInfo class ***"); string file = "my_fileinfo.txt"; //tạo một file text File.WriteAllText(file, "C Sharp Programming"); //đọc nội dung file Console.WriteLine("Read file:"); string content = File.ReadAllText(file); Console.WriteLine(content); Console.WriteLine("File information:"); //Lấy thông tin file: FileInfo fileInfo= new FileInfo(file); Console.WriteLine($"Name: {fileInfo.Name}"); //thời gian tạo: Console.WriteLine($"Creation time: {fileInfo.CreationTime}"); //thời gian ghi gần nhất: Console.WriteLine($"Last write time: {fileInfo.LastWriteTime}"); //thư mục chứa: Console.WriteLine($"Directory name: {fileInfo.DirectoryName}"); } } }
Kết quả:
*** Demo FileInfo class *** Read file: C Sharp Programming File information: Name: my_fileinfo.txt Creation time: 3/16/2030 3:37:20 PM Last write time: 3/16/2030 3:37:20 PM Directory name: D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0
Làm việc với lớp Directory
Lớp Directory bao gồm các phương thức tĩnh để tạo, di chuyển và liệt kê thông qua các thư mục và thư mục con. Lớp này không thể được thừa kế.
Dưới đây là các phương thức quan trọng của lớp Directory:
Phương thức |
Mô tả |
---|---|
CreateDirectory(String) |
Tạo tất cả các thư mục và thư mục con trong đường dẫn đã chỉ định trừ khi chúng đã tồn tại. |
Delete(String) |
Xóa một thư mục trống khỏi một đường dẫn cụ thể. |
EnumerateDirectories(String) |
Trả về một tập hợp tên đầy đủ của thư mục trong một đường dẫn cụ thể. |
EnumerateFiles(String) | Trả về một tập hợp tên đầy đủ của thư mục trong một đường dẫn cụ thể. |
Exists(String) | Xác định xem đường dẫn đã cho có tham chiếu đến một thư mục hiện có trên đĩa hay không. |
GetCurrentDirectory() | Nhận thư mục làm việc hiện tại của ứng dụng. |
GetDirectories(String) | Trả về tên của các thư mục con (bao gồm cả đường dẫn của chúng) trong thư mục đã chỉ định. |
GetFiles(String) | Trả về tên của các tệp (bao gồm cả đường dẫn của chúng) trong thư mục đã chỉ định. |
GetParent(String) | Truy xuất thư mục cha của đường dẫn đã chỉ định, bao gồm cả đường dẫn tuyệt đối và tương đối. |
Move(String, String) | Di chuyển một tập tin hoặc một thư mục và nội dung của nó đến một vị trí mới. |
Ví dụ demo về lớp Directory
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { //lấy thư mục hiện thời string currentDirectory = Directory.GetCurrentDirectory(); try { //lấy các file của thư mục var files = Directory.EnumerateFiles(currentDirectory); foreach (var file in files) { Console.WriteLine(file); } }catch(Exception ex) { Console.WriteLine(ex.Message); } } } }
Kết quả:
D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.deps.json D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.dll D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.exe D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.pdb D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.runtimeconfig.json D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\demo_filestream.dat D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\mydata.txt D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\myfile.dat D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\myfile.txt D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\my_fileinfo.txt D:\Courses\C#\Demo\ConsoleApp1\bin\Debug\net6.0\test.dat
Làm việc với lớp DirectoryInfo
Lớp DirectoryInfo bao gồm các phương thức thể hiện để tạo, di chuyển và liệt kê thông qua các thư mục và thư mục con. Lớp này không thể được thừa kế.
Các thuộc tính quan trọng của lớp DirectoryInfo
Thuộc tính |
Mô tả |
---|---|
Attributes |
Nhận hoặc đặt thuộc tính cho tệp hoặc thư mục hiện tại. |
CreationTime |
Nhận hoặc đặt thời gian tạo của tệp hoặc thư mục hiện tại. |
Exists |
Nhận một giá trị cho biết thư mục có tồn tại hay không. |
Extension |
Nhận chuỗi đại diện cho phần mở rộng của tệp. |
FullName |
Nhận đường dẫn đầy đủ của thư mục hoặc tệp |
Các phương thức quan trọng của lớp DirectoryInfo
Phương thức |
Mô tả |
---|---|
Create() |
Tạo một thư mục |
CreateSubdirectory(String) |
Tạo một thư mục con hoặc nhiều thư mục con trên đường dẫn đã chỉ định. Đường dẫn được chỉ định có thể liên quan đến phiên bản này của lớp DirectoryInfo. |
Delete() |
Xóa DirectoryInfo này nếu nó trống. |
GetDirectories(String) |
Trả về một mảng các thư mục trong DirectoryInfo hiện tại phù hợp với tiêu chí tìm kiếm đã cho. |
GetFiles(String) |
Trả về danh sách tệp từ thư mục hiện tại khớp với mẫu tìm kiếm đã cho. |
MoveTo(String) |
Di chuyển một phiên bản DirectoryInfo và nội dung của nó sang một đường dẫn mới. |
GetFileSystemInfos(String) |
Truy xuất một mảng các đối tượng FileSystemInfo có kiểu mạnh đại diện cho các tệp và thư mục con khớp với tiêu chí tìm kiếm đã chỉ định. |
Ví dụ về lớp DirectoryInfo
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { //lấy thông tin thư mục: DirectoryInfo di = new DirectoryInfo(@"D:\Courses\C#"); //tìm những thư mục có tên bắt đầu bằng Console Console.WriteLine("Search pattern Console* returns:"); foreach(var fi in di.GetDirectories("Console*")) { Console.WriteLine(fi.Name); } //lấy thông tin thư mục: di = new DirectoryInfo(@"D:\Courses\C#\Demo\Demo"); Console.WriteLine(); Console.WriteLine("Search pattern TopDirectoryOnly returns:"); foreach(var fi in di.GetFiles("*.cs", SearchOption.TopDirectoryOnly)) { Console.WriteLine(fi.Name); } } } }
Kết quả:
Search pattern Console* returns: Console ConsoleApp1 ConsoleApp2 ConsoleApp3 ConsoleApp4 Search pattern TopDirectoryOnly returns: Demo1.cs Demo2.cs Demo3.cs Program.cs
Làm việc với StreamReader và StreamWriter
StreamReader
StreamReader là lớp trợ giúp để đọc các ký tự từ stream bằng cách chuyển đổi byte thành ký tự bằng giá trị được mã hóa. Nó có thể được sử dụng để đọc các chuỗi (ký tự) từ các stream khác nhau như FileStream, MemoryStream, v.v.
StreamWriter
StreamWriter là một lớp trợ giúp để ghi một chuỗi vào stream bằng cách chuyển đổi các ký tự thành byte. Nó có thể được sử dụng để ghi các chuỗi vào các stream khác nhau như FileStream, MemoryStream, v.v.
Ví dụ về StreamReader và StreamWriter
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { string input = null; string file = @"streamreader_streamwriter.txt"; Console.WriteLine("*** Demo StreamReader and StreamWriter ***"); //Tạo một StreamWriter và ghi dữ liệu chuỗi using StreamWriter sw = new StreamWriter(file); sw.WriteLine("V1"); sw.WriteLine("Study"); sw.WriteLine("!"); for (int i = 1; i <= 10; i++) { sw.Write(i + " "); } //Chèn một dòng mới sw.Write(sw.NewLine); sw.Close(); Console.WriteLine("File was created"); Console.WriteLine("****************"); Console.WriteLine("Now read data from file:"); using StreamReader sr = new StreamReader(file); while ((input = sr.ReadLine()) != null) { Console.WriteLine(input); } sr.Close(); } } }
Kết quả:
*** Demo StreamReader and StreamWriter *** File was created **************** Now read data from file: V1 Study ! 1 2 3 4 5 6 7 8 9 10
Làm việc với BinaryReader và BinaryWriter
BinaryReader và BinaryWriter cho phép đọc và ghi các loại dữ liệu riêng biệt vào stream ở định dạng nhị phân nhỏ gọn.
Sau đây là ví dụ về BinaryReader và BinaryWriter:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { string file = @"binaryreader_binarywriter.txt"; Console.WriteLine("*** Demo BinaryReader and BinaryWriter ***"); //mở trình ghi nhị phân cho file FileInfo fi = new FileInfo(file); using BinaryWriter bw = new BinaryWriter(fi.OpenWrite()); //in ra kiểu của BaseStream Console.WriteLine($"Base stream is: {bw.BaseStream}"); //tạo một số dữ liệu để lưu vào file double aDouble = 123.456; int anInt = 789; string aString = "X, Y, Z"; //ghi dữ liệu ra file bw.Write(aDouble); bw.Write(anInt); bw.Write(aString); bw.Close(); Console.WriteLine("File was created"); Console.WriteLine("Read the binary data from the stream"); using BinaryReader br = new BinaryReader(fi.OpenRead()); Console.WriteLine(br.ReadDouble()); Console.WriteLine(br.ReadInt32()); Console.WriteLine(br.ReadString()); } } }
Kết quả:
*** Demo BinaryReader and BinaryWriter *** Base stream is: System.IO.FileStream File was created Read the binary data from the stream 123.456 789 X, Y, Z