2009-05-13 48 views
7

Tôi có một tệp văn bản được viết thành một phần của trích xuất dữ liệu rất lớn. Dòng đầu tiên của tệp văn bản là số lượng "tài khoản" được trích xuất.Cách tốt nhất để thay thế văn bản trong Tệp bằng C#/.NET là gì?

Do bản chất của trích xuất này, số đó không được biết cho đến khi kết thúc quá trình, nhưng tệp có thể lớn (vài trăm meg).

Cách tốt nhất trong C#/.NET để mở tệp (trong trường hợp này là tệp văn bản đơn giản) và thay thế dữ liệu nằm trong "dòng" đầu tiên của văn bản?

LƯU Ý QUAN TRỌNG: - Tôi không cần phải thay thế "số byte cố định" - điều đó sẽ dễ dàng. Vấn đề ở đây là dữ liệu cần được chèn vào đầu tệp là biến.

LƯU Ý QUAN TRỌNG 2: - Một số người đã hỏi về/đề cập đơn giản là giữ dữ liệu trong bộ nhớ và sau đó thay thế ... tuy nhiên điều đó hoàn toàn nằm ngoài câu hỏi. Lý do tại sao quá trình này đang được cập nhật là vì thực tế là đôi khi nó bị treo khi tải một vài hợp đồng biểu diễn vào bộ nhớ.

+0

"có nghĩa là không có đệm)" bạn có chắc là bạn không thể có số 0 đứng đầu không? –

Trả lời

4

Nếu bạn có thể chèn một trình giữ chỗ mà bạn ghi đè vào cuối bằng số và khoảng trắng thực tế.

Nếu đó không phải là tùy chọn, hãy ghi dữ liệu của bạn vào tệp bộ nhớ cache trước. Khi bạn biết số thực tế tạo tệp đầu ra và nối thêm dữ liệu từ bộ nhớ cache.

+0

Có, cách duy nhất để tránh ghi dữ liệu hai lần. Nếu đó là văn bản dựa trên nên không có vấn đề, chỉ cần dự trữ một số tiền khá của không gian đầu tiên. –

+0

Đây là những gì tôi sẽ * thích * để làm (dự trữ một số không gian trống) - vấn đề duy nhất là định dạng tệp mà tôi đang viết yêu cầu chính xáC##### \ r \ n (nghĩa là không có đệm). - Câu trả lời hay. –

+1

@Timothy: nó có cho phép số không đứng đầu không? –

1

Nếu tệp được trích xuất chỉ vài trăm megabyte, thì bạn có thể dễ dàng giữ tất cả văn bản trong bộ nhớ cho đến khi quá trình trích xuất hoàn tất. Sau đó, bạn có thể viết tệp đầu ra của mình làm thao tác cuối cùng, bắt đầu với số lượng bản ghi.

+3

"chỉ một vài trăm megabyte" ??? Bạn nghiêm túc chứ ? – Cerebrus

+1

Tôi chỉ có 2 hợp đồng biểu diễn trên máy của tôi - hầu hết những người khác trong văn phòng của chúng tôi có từ 4 đến 8. 200MB là gì. Có lẽ 10% tổng số bộ nhớ ... –

+0

Và điều gì sẽ xảy ra trong một năm khi tập tin là "chỉ một vài gigabyte", bạn sẽ giữ nó tất cả trong bộ nhớ sau đó quá? –

2

Tôi không cần phải thay thế một " số tiền cố định của byte"

Bạn có chắc chắn? Nếu bạn viết một số lớn vào dòng đầu tiên của tệp (UInt32.MaxValue hoặc UInt64.MaxValue), thì khi bạn tìm đúng số thực, bạn có thể thay thế số byte đó bằng đúng số, nhưng còn lại với các số 0 , do đó, nó vẫn là một số nguyên hợp lệ. ví dụ:

Replace 999999 - your "large number placeholder" 
With  000100 - the actual number of accounts 
+0

Giải pháp thông minh! - Tuy nhiên, thông số tập tin mà tôi đang làm việc với sẽ không chấp nhận rằng ... suy nghĩ rất tốt mặc dù :) –

+0

Bạn có nhớ tôi hỏi tại sao không? –

+0

Đó là một đặc tả tập tin, nó không trả lời câu hỏi của tôi: P –

3

BEST là rất chủ quan. Đối với bất kỳ tập tin nhỏ, bạn có thể dễ dàng mở toàn bộ tập tin trong bộ nhớ và thay thế những gì bạn muốn bằng cách sử dụng một chuỗi thay thế và sau đó viết lại tập tin.

Ngay cả đối với các tệp lớn, sẽ không khó tải vào bộ nhớ. Trong những ngày có nhiều bộ nhớ, tôi sẽ xem xét hàng trăm megabyte vẫn dễ dàng thực hiện trong bộ nhớ.

Bạn đã thử nghiệm cách tiếp cận ngây thơ này chưa? Bạn đã nhìn thấy một vấn đề thực sự với nó?

Nếu đây là tệp thực sự lớn (gigabyte), tôi sẽ xem xét ghi tất cả dữ liệu trước vào tệp tạm thời và sau đó ghi tệp chính xác với dòng tiêu đề vào trước và sau đó thêm phần còn lại của dữ liệu. Vì đó chỉ là văn bản, tôi có lẽ sẽ chỉ xuất hiện trong DOS:

TYPE temp.txt >> outfile.txt 
2

Dường như với tôi nếu tôi hiểu câu hỏi đúng?

Cách tốt nhất trong C#/.NET để mở tệp (trong trường hợp này là tệp văn bản đơn giản) và thay thế dữ liệu nằm trong "dòng" đầu tiên của văn bản?

Cách đặt ở đầu tệp là mã thông báo {UserCount} khi nó được tạo lần đầu tiên.

Sau đó, sử dụng TextReader để đọc từng dòng tệp. Nếu đây là dòng đầu tiên tìm kiếm {UserCount} và thay thế bằng giá trị của bạn. Viết ra mỗi dòng bạn đọc trong việc sử dụng TextWriter

Ví dụ:

int lineNumber = 1; 
    int userCount = 1234; 
    string line = null; 

    using(TextReader tr = File.OpenText("OriginalFile")) 
    using(TextWriter tw = File.CreateText("ResultFile")) 
    { 

     while((line = tr.ReadLine()) != null) 
     { 
      if(lineNumber == 1) 
      { 
       line = line.Replace("{UserCount}", userCount.ToString()); 
      } 

      tw.WriteLine(line); 
      lineNumber++; 
     } 

    } 
+0

Đây thực chất là những gì tôi phải làm, nhưng mục tiêu của tôi là * không * phải tạo 2 tệp. –

+0

Tôi có thêm một giải pháp mà tôi đã xem nhưng chưa được xác minh hoặc thử. Về cơ bản những gì bạn làm là sử dụng một cái gì đó giống như StreamWriter dòng để viết tập tin đầu tiên của bạn và giữ cho nó mở.Cũng viết như tôi đã đề xuất trình giữ chỗ và giữ điểm bắt đầu và điểm kết thúc của mã thông báo. Vì vậy, bây giờ bạn đang ở phần cuối của tập tin và bạn có UserCount và chỉ cần quay trở lại và thay thế các mã thông báo với giá trị của bạn. Để làm điều đó bạn sử dụng một BitStream mà tôi tin rằng bạn có thể truy cập bằng cách truy cập StreamWriter.BaseStream và có thể ghi các byte vào vị trí cụ thể trong luồng của bạn. Sẽ thử và thử nghiệm nó ra và đăng bài. –

1

Ok, trước đó tôi đề nghị một phương pháp đó sẽ là tốt hơn nếu làm việc với các tập tin hiện có.

Tuy nhiên trong trường hợp bạn muốn tạo tệp và trong quá trình tạo, hãy quay lại đầu và ghi số người dùng. Điều này sẽ làm điều đó.

Dưới đây là một cách để thực hiện điều đó ngăn bạn phải ghi tệp tạm thời.

private void WriteUsers() 
    { 
     string userCountString = null; 
     ASCIIEncoding enc = new ASCIIEncoding(); 
     byte[] userCountBytes = null; 
     int userCounter = 0; 

     using(StreamWriter sw = File.CreateText("myfile.txt")) 
     { 
      // Write a blank line and return 
      // Note this line will later contain our user count. 
      sw.WriteLine(); 

      // Write out the records and keep track of the count 
      for(int i = 1; i < 100; i++) 
      { 
       sw.WriteLine("User" + i); 
       userCounter++; 
      } 

      // Get the base stream and set the position to 0 
      sw.BaseStream.Position = 0; 

      userCountString = "User Count: " + userCounter; 

      userCountBytes = enc.GetBytes(userCountString); 

      sw.BaseStream.Write(userCountBytes, 0, userCountBytes.Length); 
     } 

    } 
+0

Thực tế đó là câu trả lời duy nhất trả lời yêu cầu chỉnh sửa tệp hiện có ... Cảm ơn! – ephraim

Các vấn đề liên quan