문제

특정 위치에 특정 문자를 삽입해야 하는 대용량 파일이 있습니다.전체 파일을 다시 작성하지 않고 C#에서 이를 수행하는 가장 쉬운 방법은 무엇입니까?

도움이 되었습니까?

해결책

파일 시스템은 파일 중간에 데이터 "삽입"을 지원하지 않습니다.정렬된 방식으로 기록할 수 있는 파일이 정말로 필요하다면 내장된 데이터베이스를 사용해 보는 것이 좋습니다.

당신은 살펴보고 싶을 수도 있습니다 SQLite 또는 버클리DB.

그런 다음 다시 텍스트 파일이나 레거시 바이너리 파일로 작업할 수도 있습니다.이 경우 유일한 옵션은 적어도 삽입 지점부터 끝까지 파일을 다시 작성하는 것입니다.

나는 파일스트림 C#에서 임의 I/O를 수행하는 클래스입니다.

다른 팁

변경 사항을 삽입한 시점부터 끝까지 파일을 다시 작성해야 할 수도 있습니다.항상 파일 끝에 쓰고 정렬 및 grep과 같은 도구를 사용하여 원하는 순서로 데이터를 가져오는 것이 가장 좋습니다.여기서는 바이너리 파일이 아닌 텍스트 파일에 대해 이야기하고 있다고 가정합니다.

문자를 다시 쓰지 않고 파일에 문자를 삽입할 수 있는 방법은 없습니다.C#을 사용하면 모든 Stream 클래스로 수행할 수 있습니다.파일이 크다면 C# 코드 내에서 GNU Core Utils를 사용하는 것이 좋습니다.그들은 가장 빠릅니다.나는 핵심 유틸리티(크기 4GB, 8GB 이상 등)를 사용하여 매우 큰 텍스트 파일을 처리하곤 했습니다.head, tail, Split, csplit, cat, shuf, shred, uniq와 같은 명령은 텍스트 조작에 많은 도움이 됩니다.

예를 들어 2GB 파일에 일부 문자를 넣어야 하는 경우 분할 -b BYTECOUNT를 사용하고 출력을 파일에 넣은 다음 새 텍스트를 추가하고 나머지 콘텐츠를 가져와 추가할 수 있습니다.이것은 아마도 다른 어떤 방법보다 더 빠를 것입니다.

그것이 효과가 있기를 바랍니다.시도 해봐.

임의 액세스를 사용하여 파일의 특정 위치에 쓸 수 있지만 텍스트 형식으로는 쓸 수 없으며 바이트로 직접 작업해야 합니다.

새 데이터를 쓰려는 특정 위치를 알고 있다면 BinaryWriter 클래스를 사용하세요.

using (BinaryWriter bw = new BinaryWriter (File.Open (strFile, FileMode.Open)))
{
    string strNewData = "this is some new data";
    byte[] byteNewData = new byte[strNewData.Length];

    // copy contents of string to byte array
    for (var i = 0; i < strNewData.Length; i++)
    {
        byteNewData[i] = Convert.ToByte (strNewData[i]);
    }

    // write new data to file
    bw.Seek (15, SeekOrigin.Begin);  // seek to position 15
    bw.Write (byteNewData, 0, byteNewData.Length);
}

이 프로젝트를 살펴보세요:Win 데이터 검사기

기본적으로 코드는 다음과 같습니다.

// this.Stream is the stream in which you insert data

{

long position = this.Stream.Position;

long length = this.Stream.Length;

MemoryStream ms = new MemoryStream();

this.Stream.Position = 0;

DIUtils.CopyStream(this.Stream, ms, position, progressCallback);

ms.Write(data, 0, data.Length);

this.Stream.Position = position;

DIUtils.CopyStream(this.Stream, ms, this.Stream.Length - position, progressCallback);

this.Stream = ms;

}

#region Delegates

public delegate void ProgressCallback(long position, long total);

#endregion

DIUtils.cs

public static void CopyStream(Stream input, Stream output, long length, DataInspector.ProgressCallback callback)
{
    long totalsize = input.Length;
    long byteswritten = 0;
    const int size = 32768;
    byte[] buffer = new byte[size];
    int read;
    int readlen = length < size ? (int)length : size;
    while (length > 0 && (read = input.Read(buffer, 0, readlen)) > 0)
    {
        output.Write(buffer, 0, read);
        byteswritten += read;
        length -= read;
        readlen = length < size ? (int)length : size;
        if (callback != null)
            callback(byteswritten, totalsize);
    }
}

프로젝트 범위에 따라 파일과 함께 텍스트의 각 줄을 테이블 데이터 구조.일종의 데이터베이스 테이블과 비슷합니다., 이렇게 하면 언제든지 특정 위치에 삽입할 수 있으며 매번 전체 텍스트 파일을 읽고, 수정하고, 출력할 필요가 없습니다.이는 귀하의 데이터가 귀하가 말한 것처럼 "거대"하다는 사실을 전제로 합니다.여전히 파일을 다시 만들 수 있지만 최소한 이런 방식으로 확장 가능한 솔루션을 만들 수 있습니다.

파일 시스템이 파일을 저장하는 방법에 따라 중간에 바이트를 빠르게 삽입(즉, 추가 추가)하는 것이 "가능"할 수 있습니다.원격으로 가능하다면 한 번에 전체 블록을 수행하는 것이 가능하며, 파일 시스템 자체를 낮은 수준으로 수정하거나 파일 시스템별 인터페이스를 사용해야만 가능합니다.

파일 시스템은 일반적으로 이 작업을 위해 설계되지 않았습니다.삽입을 빠르게 수행해야 하는 경우에는 보다 일반적인 데이터베이스가 필요합니다.

응용 프로그램에 따라 중간 지점은 삽입물을 함께 묶는 것이므로 파일을 20개가 아닌 한 번만 다시 작성하면 됩니다.

항상 삽입 지점의 나머지 바이트를 다시 작성해야 합니다.이 지점이 0이면 전체 파일을 다시 작성하게 됩니다.마지막 바이트보다 10바이트 앞선 경우 마지막 10바이트를 다시 쓰게 됩니다.

어쨌든 "파일에 삽입"을 직접 지원하는 기능은 없습니다.그러나 다음 코드는 이를 정확하게 수행할 수 있습니다.

var sw = new Stopwatch();
var ab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ";

// create
var fs = new FileStream(@"d:\test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 262144, FileOptions.None);
sw.Restart();
fs.Seek(0, SeekOrigin.Begin);
for (var i = 0; i < 40000000; i++) fs.Write(ASCIIEncoding.ASCII.GetBytes(ab), 0, ab.Length);
sw.Stop();
Console.WriteLine("{0} ms", sw.Elapsed.TotalMilliseconds);
fs.Dispose();

// insert
fs = new FileStream(@"d:\test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 262144, FileOptions.None);
sw.Restart();
byte[] b = new byte[262144];
long target = 10, offset = fs.Length - b.Length;
while (offset != 0)
{
    if (offset < 0)
    {
        offset = b.Length - target;
        b = new byte[offset];
    }
    fs.Position = offset; fs.Read(b, 0, b.Length);
    fs.Position = offset + target; fs.Write(b, 0, b.Length);
    offset -= b.Length;
}
fs.Position = target; fs.Write(ASCIIEncoding.ASCII.GetBytes(ab), 0, ab.Length);
sw.Stop();
Console.WriteLine("{0} ms", sw.Elapsed.TotalMilliseconds);

파일 IO에 대해 더 나은 성능을 얻으려면 위 코드와 같이 "마법의 2로 구동되는 숫자"를 사용하여 플레이하십시오.파일 생성에는 전혀 도움이 되지 않는 262144바이트(256KB)의 버퍼를 사용합니다.삽입을 위한 동일한 버퍼는 코드를 실행하면 StopWatch 결과에서 볼 수 있듯이 "성능 작업"을 수행합니다.내 PC에서 초안 테스트를 수행한 결과는 다음과 같습니다.

생성에는 13628.8ms, 삽입에는 3597.0971ms가 소요됩니다.

삽입할 대상 바이트는 10입니다. 이는 거의 전체 파일이 다시 작성되었음을 의미합니다.

파일 끝(문자 그대로 현재 파일 크기보다 4바이트 높음)에 포인터를 놓은 다음 파일 끝에 삽입된 데이터의 길이와 마지막으로 삽입하려는 데이터를 쓰는 것이 어떻습니까? 그 자체.예를 들어 파일 중간에 문자열이 있고 문자열 중간에 몇 개의 문자를 삽입하려는 경우 문자열의 약 4개 문자 위에 파일 끝에 포인터를 쓴 다음 다음과 같이 쓸 수 있습니다. 처음에 삽입하려는 문자와 함께 끝까지 4개의 문자를 입력합니다.데이터 주문에 관한 것입니다.물론 전체 파일을 직접 작성하는 경우에만 이 작업을 수행할 수 있습니다. 즉, 다른 코덱을 사용하지 않는다는 의미입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top