ใช้ FileStream.SetLength() เพื่อย่อ (Truncate) หรือขยายไฟล์เป็นขนาดที่กำหนด
Syntax
public override void SetLength(long value);
พฤติกรรม
| เงื่อนไข | พฤติกรรม |
|---|---|
| Value < Current Length | ไฟล์ถูกย่อ (Truncate) - ข้อมูลเกินหายไป ถ้า Position > New Length → Position = New Length |
| Value > Current Length | ไฟล์ขยาย - พื้นที่ใหม่เป็น Undefined (Garbage) Position คงเดิม |
| Value = Current Length | ไม่เกิดอะไร |
ตัวอย่าง: ย่อไฟล์ให้เหลือ 100 Bytes
using System;
using System.IO;
public class FileTruncateExample
{
public static void TruncateFile(string path, long newSize)
{
// ต้องเปิดด้วย FileAccess.Write
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Write))
{
Console.WriteLine($"Current Length: {fs.Length}");
Console.WriteLine($"Current Position: {fs.Position}");
fs.SetLength(newSize);
Console.WriteLine($"New Length: {fs.Length}");
Console.WriteLine($"New Position: {fs.Position}");
}
}
public static void Main()
{
string path = "test.txt";
// สร้างไฟล์ทดสอบ 200 bytes
File.WriteAllBytes(path, new byte[200]);
TruncateFile(path, 100); // ย่อเหลือ 100 bytes
}
}
ตัวอย่าง: ตัดบรรทัดสุดท้ายออก (Truncate Last Line)
public static void TruncateLastLine(string path)
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
{
// หา Newline ท้ายสุด
long pos = fs.Length - 1;
byte[] buffer = new byte[1];
while (pos >= 0)
{
fs.Position = pos;
fs.Read(buffer, 0, 1);
if (buffer[0] == '\n' || buffer[0] == '\r')
{
// ตัดที่นี่ (รวม Newline)
fs.SetLength(pos + 1);
return;
}
pos--;
}
}
}
⚠️ ข้อควรระวัง
- Data Loss: Truncate ทำให้ข้อมูลหายถาวร - ไม่มี Undo
- Position: หลัง Truncate Position อาจเปลี่ยน (ถ้ามากกว่า New Length)
- Concurrency: Process อื่นอ่านไฟล์อยู่อาจ Error
- SSD Wear: เขียน/ย่อบ่อยส่งผลอายุ SSD (แต่ NTFS จัดการได้ค่อนข้างดี)
Alternative: Write New File แล้ว Replace (ปลอดภัยกว่า)
public static void SafeTruncate(string path, long newSize)
{
string tempPath = path + ".tmp";
using (var src = new FileStream(path, FileMode.Open, FileAccess.Read))
using (var dst = new FileStream(tempPath, FileMode.Create, FileAccess.Write))
{
// Copy เฉพาะส่วนที่ต้องการ
byte[] buffer = new byte[8192];
long remaining = newSize;
while (remaining > 0)
{
int toRead = (int)Math.Min(buffer.Length, remaining);
int read = src.Read(buffer, 0, toRead);
if (read == 0) break;
dst.Write(buffer, 0, read);
remaining -= read;
}
}
// Atomic Replace
File.Replace(tempPath, path, null); // Backup = null (No Backup)
}
กรณีใช้งานจริง
- Log Rotation: ย่อ Log File เมื่อใหญ่เกินไป
- Circular Buffer File: เขียนทับข้อมูลเก่า
- Temp File Cleanup: ตัดข้อมูลที่ Process เสร็จแล้ว
- Database-like: Truncate Table (Vacuum)