파일 다루기
파일 다루기
dynamic은 컴파일 타임 형식 검사를 생략하고 런타임에 형식 및 멤버 접근의 유효성을 확인하는 특별한 형식입니다. 이를 통해 정적 형식 언어인 C#에서도 동적 형식 지정의 유연성을 활용할 수 있으며, 특히 COM 상호 운용성이나 동적 언어와의 연동 시 유용합니다.
파일 정보와 디렉터리 정보 다루기
C#에서는 System.IO 네임스페이스를 통해 파일과 디렉터리를 관리할 수 있습니다. 주요 클래스로는 File, Directory, FileInfo, DirectoryInfo가 있습니다.
File/Directory: 정적 메서드를 제공하는 클래스FileInfo/DirectoryInfo: 인스턴스 메서드를 제공하는 클래스
예제 프로그램: 디렉터리/파일 정보 조회하기
using System;
using System.IO;
class FileInfoExample
{
static void Main()
{
string dirPath = @"C:\Example";
if (Directory.Exists(dirPath))
{
Console.WriteLine("디렉터리 존재함: " + dirPath);
DirectoryInfo di = new DirectoryInfo(dirPath);
Console.WriteLine("이름: " + di.Name);
Console.WriteLine("생성 시간: " + di.CreationTime);
Console.WriteLine("마지막 접근 시간: " + di.LastAccessTime);
FileInfo[] files = di.GetFiles();
Console.WriteLine("\n파일 목록:");
foreach (FileInfo file in files)
{
Console.WriteLine($"파일명: {file.Name}, 크기: {file.Length}바이트");
}
DirectoryInfo[] dirs = di.GetDirectories();
Console.WriteLine("\n하위 디렉터리 목록:");
foreach (DirectoryInfo dir in dirs)
{
Console.WriteLine($"디렉터리명: {dir.Name}");
}
}
else
{
Console.WriteLine("디렉터리가 존재하지 않습니다. " + dirPath);
}
string filePath = @"C:\Example\sample.txt";
if (File.Exists(filePath))
{
Console.WriteLine("\n파일 존재함: " + filePath);
FileInfo fi = new FileInfo(filePath);
Console.WriteLine("파일명: " + fi.Name);
Console.WriteLine("확장자: " + fi.Extension);
Console.WriteLine("크기: " + fi.Length + "바이트");
Console.WriteLine("생성 시간: " + fi.CreationTime);
Console.WriteLine("마지막 수정 시간: " + fi.LastWriteTime);
Console.WriteLine("읽기 전용: " + fi.IsReadOnly);
}
else
{
Console.WriteLine("\n파일이 존재하지 않습니다. " + filePath);
}
}
}예제 프로그램: 디렉터리/파일 생성하기
using System;
using System.IO;
class CreateFileDirectoryExample
{
static void Main()
{
string dirPath = @"C:\Example\NewFolder";
try
{
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
Console.WriteLine("디렉터리 생성됨: " + dirPath);
}
else
{
Console.WriteLine("이미 디렉터리가 존재합니다. " + dirPath);
}
string subDirPath = Path.Combine(dirPath, "SubFolder");
DirectoryInfo di = new DirectoryInfo(subDirPath);
if (!di.Exists)
{
di.Create();
Console.WriteLine("하위 디렉터리 생성됨: " + subDirPath);
}
string filePath = Path.Combine(dirPath, "newFile.txt");
if (!File.Exists(filePath))
{
File.Create(filePath).Close();
Console.WriteLine("빈 파일 생성됨: " + filePath);
string textFilePath = Path.Combine(dirPath, "textFile.txt");
File.WriteAllText(textFilePath, "안녕하세요. 이것은 텍스트 파일입니다.");
Console.WriteLine("텍스트 파일 생성됨: " + textFilePath);
string binaryFilePath = Path.Combine(dirPath, "binaryFile.dat");
byte[] bytes = new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F }; // "Hello"의 ASCII 코드
File.WriteAllBytes(binaryFilePath, bytes);
Console.WriteLine("바이너리 파일 생성됨: " + binaryFilePath);
}
string anotherFilePath = Path.Combine(dirPath, "anotherFile.txt");
FileInfo fi = new FileInfo(anotherFilePath);
if (!fi.Exists)
{
using (StreamWriter sw = fi.CreateText())
{
sw.WriteLine("FileInfo 클래스를 사용한 파일 생성");
}
Console.WriteLine("FileInfo로 파일 생성됨: " + anotherFilePath);
}
string copyFilePath = Path.Combine(dirPath, "copyFile.txt");
fi.CopyTo(copyFilePath, true); // true: 기존 파일 덮어쓰기
Console.WriteLine("파일 복사됨: " + copyFilePath);
string moveFilePath = Path.Combine(subDirPath, "movedFile.txt");
fi.MoveTo(moveFilePath);
Console.WriteLine("파일 이동됨: " + moveFilePath);
}
catch (Exception ex)
{
Console.WriteLine("오류 발생: " + ex.Message);
}
}
}System.IO.Stream 클래스
Stream은 모든 입출력 작업의 기본이 되는 추상 클래스입니다. 대표적인 파생 클래스는 다음과 같습니다.
FileStream: 파일에서 데이터를 읽고 쓰는 스트림MemoryStream: 메모리에서 데이터를 읽고 쓰는 스트림NetworkStream: 네트워크 소켓에서 데이터를 읽고 쓰는 스트림BufferedStream: 버퍼를 사용하여 읽기/쓰기 성능을 향상시키는 스트림
using System;
using System.IO;
class StreamExample
{
static void Main()
{
string filePath = @"C:\Example\stream.dat";
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
byte[] data = new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F }; // "Hello"
fs.Write(data, 0, data.Length);
Console.WriteLine($"{data.Length}바이트를 파일에 작성했습니다.");
}
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[fs.Length];
int bytesRead = fs.Read(buffer, 0, buffer.Length);
Console.WriteLine($"{bytesRead}바이트를 파일에서 읽었습니다.");
Console.Write("데이터: ");
foreach (byte b in buffer)
{
Console.Write($"{b:X2} ");
}
Console.WriteLine();
string text = System.Text.Encoding.ASCII.GetString(buffer);
Console.WriteLine("텍스트: " + text);
}
using (MemoryStream ms = new MemoryStream())
{
byte[] data = new byte[] { 0x57, 0x6F, 0x72, 0x6C, 0x64 }; // "World"
ms.Write(data, 0, data.Length);
ms.Position = 0;
byte[] buffer = new byte[ms.Length];
ms.Read(buffer, 0, buffer.Length);
string text = System.Text.Encoding.ASCII.GetString(buffer);
Console.WriteLine("MemoryStream 데이터: " + text);
}
}
}실수를 줄여주는 using 선언
using 문은 IDisposable 인터페이스를 구현하는 객체의 Dispose 메서드가 자동으로 호출되도록 보장합니다. 이는 파일 핸들과 같은 자원을 안전하게 해제하는 데 매우 중요합니다.
using System;
using System.IO;
class UsingExample
{
static void Main()
{
string filePath = @"C:\Example\using_example.txt";
using (StreamWriter writer = new StreamWriter(filePath))
{
writer.WriteLine("이것은 전통적인 using 문입니다.");
}
void UsingDeclaration()
{
using StreamReader reader = new StreamReader(filePath);
string line = reader.ReadLine();
Console.WriteLine("읽은 내용: " + line);
}
UsingDeclaration();
void TryFinallyExample()
{
StreamWriter writer = null;
try
{
writer = new StreamWriter(filePath, true);
writer.WriteLine("이것은 try-finally 예제입니다.");
}
finally
{
if (writer != null)
{
writer.Dispose();
}
}
}
TryFinallyExample();
using (StreamWriter writer = new StreamWriter(filePath, true))
using (StreamReader reader = new StreamReader(@"C:\Example\input.txt"))
{
string line = reader.ReadLine();
if (line != null)
{
writer.WriteLine("복사된 내용: " + line);
}
}
}
}이진 데이터 처리를 위한 BinaryWriter/BinaryReader
BinaryWriter와 BinaryReader는 기본 데이터 타입을 이진 형식으로 쓰고 읽을 수 있게 해주는 클래스입니다.
using System;
using System.IO;
class BinaryIOExample
{
static void Main()
{
string filePath = @"C:\Example\binary_data.bin";
using (FileStream fs = new FileStream(filePath, FileMode.Create))
using (BinaryWriter writer = new BinaryWriter(fs))
{
writer.Write(42); // int
writer.Write(3.14159); // double
writer.Write(true); // bool
writer.Write("안녕하세요"); // string
writer.Write(new byte[] { 0x01, 0x02, 0x03 }); // byte[]
Console.WriteLine("이진 데이터 쓰기 완료.");
}
using (FileStream fs = new FileStream(filePath, FileMode.Open))
using (BinaryReader reader = new BinaryReader(fs))
{
int intValue = reader.ReadInt32();
double doubleValue = reader.ReadDouble();
bool boolValue = reader.ReadBoolean();
string stringValue = reader.ReadString();
byte[] byteArray = reader.ReadBytes(3);
Console.WriteLine($"읽은 정수: {intValue}");
Console.WriteLine($"읽은 실수: {doubleValue}");
Console.WriteLine($"읽은 불리언: {boolValue}");
Console.WriteLine($"읽은 문자열: {stringValue}");
Console.Write("읽은 바이트 배열: ");
foreach (byte b in byteArray)
{
Console.Write($"{b:X2} ");
}
Console.WriteLine();
}
using (FileStream fs = new FileStream(filePath, FileMode.Create))
using (BinaryWriter writer = new BinaryWriter(fs))
{
Person person = new Person
{
Id = 1001,
Name = "홍길동",
Age = 30,
Salary = 5000000.50
};
writer.Write(person.Id);
writer.Write(person.Name);
writer.Write(person.Age);
writer.Write(person.Salary);
Console.WriteLine("구조체 데이터 쓰기 완료.");
}
using (FileStream fs = new FileStream(filePath, FileMode.Open))
using (BinaryReader reader = new BinaryReader(fs))
{
Person person = new Person
{
Id = reader.ReadInt32(),
Name = reader.ReadString(),
Age = reader.ReadInt32(),
Salary = reader.ReadDouble()
};
Console.WriteLine("\n구조체 데이터 읽기 결과:");
Console.WriteLine($"ID: {person.Id}");
Console.WriteLine($"이름: {person.Name}");
Console.WriteLine($"나이: {person.Age}");
Console.WriteLine($"급여: {person.Salary:C}");
}
}
struct Person
{
public int Id;
public string Name;
public int Age;
public double Salary;
}
}텍스트 파일 처리를 위한 StreamWriter/StreamReader
StreamWriter와 StreamReader는 텍스트 파일을 다루기 위한 고수준 클래스입니다.
using System;
using System.IO;
using System.Text;
class TextFileExample
{
static void Main()
{
string filePath = @"C:\Example\text_file.txt";
using (StreamWriter writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
writer.WriteLine("안녕하세요! StreamWriter 예제입니다.");
writer.WriteLine("두 번째 줄입니다.");
writer.WriteLine("숫자: {0}, 실수: {1:F2}", 42, 3.14159);
for (int i = 1; i <= 5; i++)
{
writer.Write(i + " ");
}
writer.WriteLine();
writer.WriteLine("파일의 마지막 줄입니다.");
Console.WriteLine("텍스트 파일 쓰기 완료.");
}
using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8))
{
Console.WriteLine("\n파일 내용 (한 줄씩 읽기):");
int lineNumber = 1;
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine($"{lineNumber++}: {line}");
}
}
string allText = File.ReadAllText(filePath, Encoding.UTF8);
Console.WriteLine("\n파일 전체 내용:");
Console.WriteLine(allText);
string[] allLines = File.ReadAllLines(filePath, Encoding.UTF8);
Console.WriteLine("\n파일 줄 배열 (인덱스 접근):");
for (int i = 0; i < allLines.Length; i++)
{
Console.WriteLine($"줄 {i}: {allLines[i]}");
}
using (StreamWriter writer = new StreamWriter(filePath, true, Encoding.UTF8))
{
writer.WriteLine("\n이 텍스트는 기존 파일에 추가됩니다.");
Console.WriteLine("파일에 텍스트 추가 완료.");
}
using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8))
{
Console.WriteLine("\n파일 내용 (문자 단위 읽기, 처음 20자):");
for (int i = 0; i < 20; i++)
{
int charCode = reader.Read();
if (charCode == -1) break; // 파일의 끝
Console.Write((char)charCode);
}
Console.WriteLine("...");
}
}
}객체 직렬화하기
객체 직렬화는 객체의 상태를 바이트 스트림으로 변환하여 파일, 메모리, 네트워크 등에 저장하거나 전송할 수 있게 해주는 기술입니다.
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;
using System.Text.Json;
[Serializable]
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
[NonSerialized]
private string password;
public Person() { }
public Person(int id, string name, int age)
{
Id = id;
Name = name;
Age = age;
}
public override string ToString()
{
return $"Id: {Id}, 이름: {Name}, 나이: {Age}";
}
}
[Serializable]
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
[XmlIgnore]
public string SecretCode { get; set; }
public Product() { }
public Product(int id, string name, decimal price)
{
ProductId = id;
Name = name;
Price = price;
}
public override string ToString()
{
return $"제품 ID: {ProductId}, 이름: {Name}, 가격: {Price:C}";
}
}
class SerializationExample
{
static void Main()
{
string binaryFilePath = @"C:\Example\person.bin";
string xmlFilePath = @"C:\Example\product.xml";
string jsonFilePath = @"C:\Example\product.json";
Person person = new Person(1, "홍길동", 30);
Console.WriteLine("원본 객체: " + person);
BinarySerialize(person, binaryFilePath);
Person deserializedPerson = BinaryDeserialize(binaryFilePath);
Console.WriteLine("역직렬화된 객체: " + deserializedPerson);
Product product = new Product(101, "노트북", 1500000);
product.SecretCode = "SECRET123"; // 직렬화에서 제외됨
Console.WriteLine("\n원본 제품: " + product);
XmlSerialize(product, xmlFilePath);
Product deserializedProduct = XmlDeserialize<Product>(xmlFilePath);
Console.WriteLine("역직렬화된 제품: " + deserializedProduct);
Console.WriteLine("SecretCode (XML 무시됨): " + deserializedProduct.SecretCode);
JsonSerialize(product, jsonFilePath);
Product deserializedJsonProduct = JsonDeserialize<Product>(jsonFilePath);
Console.WriteLine("\nJSON 역직렬화된 제품: " + deserializedJsonProduct);
}
static void BinarySerialize(object obj, string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, obj);
Console.WriteLine($"객체를 이진 형식으로 직렬화 완료: {filePath}");
}
}
static T BinaryDeserialize<T>(string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
BinaryFormatter formatter = new BinaryFormatter();
return (T)formatter.Deserialize(fs);
}
}
static void XmlSerialize<T>(T obj, string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
serializer.Serialize(fs, obj);
Console.WriteLine($"객체를 XML 형식으로 직렬화 완료: {filePath}");
}
}
static T XmlDeserialize<T>(string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(fs);
}
}
static void JsonSerialize<T>(T obj, string filePath)
{
string jsonString = JsonSerializer.Serialize(obj, new JsonSerializerOptions
{
WriteIndented = true // 들여쓰기 적용
});
File.WriteAllText(filePath, jsonString);
Console.WriteLine($"객체를 JSON 형식으로 직렬화 완료: {filePath}");
}
static T JsonDeserialize<T>(string filePath)
{
string jsonString = File.ReadAllText(filePath);
return JsonSerializer.Deserialize<T>(jsonString);
}
}비동기 파일 입출력
현대 애플리케이션에서는 UI 응답성을 유지하고 자원을 효율적으로 사용하기 위해 비동기 파일 입출력이 중요합니다. C#에서는 async와 await 키워드를 통해 비동기 프로그래밍을 쉽게 구현할 수 있습니다.
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
class AsyncFileIOExample
{
static async Task Main()
{
string filePath = @"C:\Example\async_file.txt";
await WriteFileAsync(filePath);
string content = await ReadFileAsync(filePath);
Console.WriteLine("파일 내용:");
Console.WriteLine(content);
await ProcessMultipleFilesAsync();
}
static async Task WriteFileAsync(string filePath)
{
Console.WriteLine("파일 쓰기 시작...");
string content = "이것은 비동기로 작성된 파일입니다.\n";
for (int i = 1; i <= 10; i++)
{
content += $"비동기 작업 라인 {i}\n";
}
using (StreamWriter writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
await writer.WriteAsync(content);
}
Console.WriteLine("파일 쓰기 완료.");
}
static async Task<string> ReadFileAsync(string filePath)
{
Console.WriteLine("파일 읽기 시작...");
string content;
using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8))
{
content = await reader.ReadToEndAsync();
}
Console.WriteLine("파일 읽기 완료.");
return content;
}
static async Task ProcessMultipleFilesAsync()
{
string[] files = new string[]
{
@"C:\Example\async_file1.txt",
@"C:\Example\async_file2.txt",
@"C:\Example\async_file3.txt"
};
var writeTasks = new Task[files.Length];
for (int i = 0; i < files.Length; i++)
{
string content = $"이것은 파일 {i+1}의 내용입니다.\n";
writeTasks[i] = File.WriteAllTextAsync(files[i], content);
}
Console.WriteLine("여러 파일 동시에 쓰기 시작...");
await Task.WhenAll(writeTasks);
Console.WriteLine("모든 파일 쓰기 완료.");
var readTasks = new Task<string>[files.Length];
for (int i = 0; i < files.Length; i++)
{
readTasks[i] = File.ReadAllTextAsync(files[i]);
}
Console.WriteLine("여러 파일 동시에 읽기 시작...");
string[] contents = await Task.WhenAll(readTasks);
Console.WriteLine("모든 파일 읽기 완료.");
for (int i = 0; i < contents.Length; i++)
{
Console.WriteLine($"파일 {i+1} 내용: {contents[i]}");
}
}
}파일 감시하기 (FileSystemWatcher)
FileSystemWatcher 클래스를 사용하면 특정 디렉터리나 파일의 변경사항을 감지하고 대응할 수 있습니다.
using System;
using System.IO;
class FileWatcherExample
{
static void Main()
{
string directoryToWatch = @"C:\Example";
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
watcher.Path = directoryToWatch;
watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName |
NotifyFilters.LastWrite | NotifyFilters.Size;
watcher.Filter = "*.*";
watcher.IncludeSubdirectories = true;
watcher.Created += OnChanged;
watcher.Deleted += OnChanged;
watcher.Changed += OnChanged;
watcher.Renamed += OnRenamed;
watcher.EnableRaisingEvents = true;
Console.WriteLine($"'{directoryToWatch}' 디렉터리 감시 중...");
Console.WriteLine("종료하려면 아무 키나 누르세요.");
Console.ReadKey();
}
}
private static void OnChanged(object source, FileSystemEventArgs e)
{
Console.WriteLine($"[{DateTime.Now}] {e.ChangeType}: {e.FullPath}");
if (e.ChangeType == WatcherChangeTypes.Changed && File.Exists(e.FullPath))
{
try
{
FileInfo fileInfo = new FileInfo(e.FullPath);
Console.WriteLine($" 파일 크기: {fileInfo.Length} 바이트");
Console.WriteLine($" 마지막 수정 시간: {fileInfo.LastWriteTime}");
}
catch (Exception ex)
{
Console.WriteLine($" 파일 정보 읽기 실패: {ex.Message}");
}
}
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
Console.WriteLine($"[{DateTime.Now}] {e.ChangeType}: {e.OldFullPath} -> {e.FullPath}");
}
}메모리 매핑 파일 (Memory-Mapped Files)
메모리 매핑 파일은 대용량 파일을 효율적으로 다루거나 프로세스 간 통신을 위해 사용할 수 있습니다.
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Text;
class MemoryMappedFileExample
{
static void Main()
{
string filePath = @"C:\Example\mapped_file.dat";
long fileSize = 10 * 1024; // 10KB
Console.WriteLine("메모리 매핑 파일 예제 시작");
CreateFileBasedMappedFile(filePath, fileSize);
ReadMemoryMappedFile(filePath);
UseMemoryBasedMappedFile();
Console.WriteLine("\n프로세스 간 통신 예제:");
Console.WriteLine("이 예제를 실행하려면 별도의 프로세스가 필요합니다.");
Console.WriteLine("실제 코드에서는 두 개의 별도 프로그램으로 분리하여 사용하세요.");
}
static void CreateFileBasedMappedFile(string filePath, long fileSize)
{
Console.WriteLine($"\n1. 파일 기반 메모리 매핑 파일 생성: {filePath} ({fileSize} 바이트)");
try
{
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
{
fs.SetLength(fileSize); // 파일 크기 설정
}
using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open))
{
using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor())
{
string message = "안녕하세요! 이것은 메모리 매핑 파일 예제입니다.";
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
accessor.Write(0, messageBytes.Length);
accessor.WriteArray(4, messageBytes, 0, messageBytes.Length);
accessor.Write(1024, 12345); // int
accessor.Write(1028, 3.14159); // double
accessor.Write(1036, true); // bool
Console.WriteLine("데이터 쓰기 완료.");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"오류 발생: {ex.Message}");
}
}
static void ReadMemoryMappedFile(string filePath)
{
Console.WriteLine($"\n2. 메모리 매핑 파일 읽기: {filePath}");
try
{
using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open))
{
using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor())
{
int stringLength = accessor.ReadInt32(0);
byte[] buffer = new byte[stringLength];
accessor.ReadArray(4, buffer, 0, stringLength);
string message = Encoding.UTF8.GetString(buffer);
int intValue = accessor.ReadInt32(1024);
double doubleValue = accessor.ReadDouble(1028);
bool boolValue = accessor.ReadBoolean(1036);
Console.WriteLine($"읽은 문자열: {message}");
Console.WriteLine($"읽은 정수: {intValue}");
Console.WriteLine($"읽은 실수: {doubleValue}");
Console.WriteLine($"읽은 불리언: {boolValue}");
}
using (MemoryMappedViewStream stream = mmf.CreateViewStream(0, 0))
{
byte[] lengthBuffer = new byte[4];
stream.Read(lengthBuffer, 0, 4);
int stringLength = BitConverter.ToInt32(lengthBuffer, 0);
byte[] stringBuffer = new byte[stringLength];
stream.Read(stringBuffer, 0, stringLength);
string message = Encoding.UTF8.GetString(stringBuffer);
Console.WriteLine($"스트림을 통해 읽은 문자열: {message}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"오류 발생: {ex.Message}");
}
}
static void UseMemoryBasedMappedFile()
{
Console.WriteLine("\n3. 메모리 스트림 기반 메모리 매핑 파일");
try
{
using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("SharedMemory", 1024 * 1024))
{
using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor())
{
accessor.Write(0, 42);
accessor.Write(4, 3.14159);
accessor.Write(12, (long)9876543210);
Employee emp = new Employee
{
Id = 1001,
Salary = 5000000.50,
IsActive = true
};
accessor.Write(100, emp.Id);
accessor.Write(104, emp.Salary);
accessor.Write(112, emp.IsActive);
Console.WriteLine("메모리 매핑 파일에 데이터 쓰기 완료.");
}
using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor())
{
int intValue = accessor.ReadInt32(0);
double doubleValue = accessor.ReadDouble(4);
long longValue = accessor.ReadInt64(12);
Employee emp = new Employee
{
Id = accessor.ReadInt32(100),
Salary = accessor.ReadDouble(104),
IsActive = accessor.ReadBoolean(112)
};
Console.WriteLine($"읽은 값: {intValue}, {doubleValue}, {longValue}");
Console.WriteLine($"읽은 구조체: Id={emp.Id}, Salary={emp.Salary}, IsActive={emp.IsActive}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"오류 발생: {ex.Message}");
}
}
static void IpcServerExample()
{
using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("SharedMemoryIPC", 4096))
{
using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor())
{
string message = "서버에서 보낸 메시지";
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
accessor.Write(0, messageBytes.Length);
accessor.WriteArray(4, messageBytes, 0, messageBytes.Length);
Console.WriteLine("서버: 데이터 기록 완료. 클라이언트 대기 중...");
Console.ReadKey();
}
}
}
static void IpcClientExample()
{
using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("SharedMemoryIPC"))
{
using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor())
{
int messageLength = accessor.ReadInt32(0);
byte[] buffer = new byte[messageLength];
accessor.ReadArray(4, buffer, 0, messageLength);
string message = Encoding.UTF8.GetString(buffer);
Console.WriteLine($"클라이언트: 서버에서 받은 메시지: {message}");
}
}
}
struct Employee
{
public int Id;
public double Salary;
public bool IsActive;
}
}