2011-12-20 39 views
15

Tôi có hàng triệu dòng tạo ra từ dữ liệu được cập nhật mỗi giây mà trông như thế này:dòng Thao tác dữ liệu

104500 4783 
104501 8930 
104502 21794 
104503 21927 
104505 5746 
104506 9968 
104509 5867 
104510 46353 
104511 7767 
104512 4903 

Cột bên trái tượng trưng cho thời gian (định dạng HHMMSS), và cột bên phải là dữ liệu được cập nhật từng giây một. Như bạn có thể thấy tuy nhiên, nó không phải là thực sự từng giây, và có một số lần mất tích (10:45:04, 10:45:07, 10:45:08 là mất tích trong ví dụ này). Mục tiêu của tôi là thêm vào các giây còn thiếu và sử dụng dữ liệu từ giây trước đó cho số giây còn thiếu đó, như sau:

104500 4783 
104501 8930 
104502 21794 
104503 21927 
104504 21927 -- 
104505 5746 
104506 9968 
104507 9968 -- 
104508 9968 -- 
104509 5867 
104510 46353 
104511 7767 
104512 4903 

Tôi không muốn "-" trong kết quả, tôi chỉ đặt những dấu đó vào đó để đánh dấu các dòng được thêm vào. Cho đến nay tôi đã cố gắng để thực hiện điều này bằng cách sử dụng StreamReader và StreamWriter, nhưng nó không có vẻ như họ đang đi để có được tôi những gì tôi muốn. Tôi là một lập trình viên newbie và một newbie để C#, vì vậy nếu bạn chỉ có thể chỉ cho tôi đi đúng hướng, đó sẽ là tuyệt vời. Tôi thực sự chỉ tự hỏi nếu điều này thậm chí có thể làm trong C# ... Tôi đã dành rất nhiều thời gian trên MSDN và ở đây trên SO tìm kiếm một giải pháp này, nhưng cho đến nay đã không tìm thấy bất kỳ.

Chỉnh sửa: Các dòng nằm trong tệp văn bản và tôi muốn lưu trữ dữ liệu mới được tạo trong tệp văn bản mới.

+0

Tôi giả sử các dòng này là từ một tập tin văn bản và bạn muốn tạo một hình mới với các giá trị thiếu? – Strillo

+6

+1 cho câu hỏi đầu tiên tuyệt vời (được viết, giải thích và định dạng). –

+0

Vâng, xin lỗi, tôi nên đưa nó vào câu hỏi của tôi. Các dòng nằm trong một tệp văn bản và tôi muốn lưu trữ dữ liệu mới được tạo trong một tệp văn bản mới. –

Trả lời

3

ok, đây là toàn bộ trận đấu bắn súng, kiểm tra và làm việc với dữ liệu thử nghiệm của bạn:

public void InjectMissingData() 
{ 
    DataLine lastDataLine = null; 
    using (var writer = new StreamWriter(File.Create("c:\\temp\\out.txt"))) 
    { 
     using (var reader = new StreamReader("c:\\temp\\in.txt")) 
     { 
      while (!reader.EndOfStream) 
      { 
       var dataLine = DataLine.Parse(reader.ReadLine()); 

       while (lastDataLine != null && dataLine.Occurence - lastDataLine.Occurence > TimeSpan.FromSeconds(1)) 
       { 
        lastDataLine = new DataLine(lastDataLine.Occurence + TimeSpan.FromSeconds(1), lastDataLine.Data); 
        writer.WriteLine(lastDataLine.Line); 
       } 

       writer.WriteLine(dataLine.Line); 

       lastDataLine = dataLine; 
      } 
     } 
    } 
} 

public class DataLine 
{ 
    public static DataLine Parse(string line) 
    { 
     var timeString = string.Format("{0}:{1}:{2}", line.Substring(0, 2), line.Substring(2, 2), 
             line.Substring(4, 2)); 

     return new DataLine(TimeSpan.Parse(timeString), long.Parse(line.Substring(7, line.Length - 7).Trim())); 
    } 

    public DataLine(TimeSpan occurence, long data) 
    { 
     Occurence = occurence; 
     Data = data; 
    } 

    public TimeSpan Occurence { get; private set; } 
    public long Data { get; private set; } 

    public string Line 
    { 
     get { return string.Format("{0}{1}{2} {3}", 
      Occurence.Hours.ToString().PadLeft(2, Char.Parse("0")), 
      Occurence.Minutes.ToString().PadLeft(2, Char.Parse("0")), 
      Occurence.Seconds.ToString().PadLeft(2, Char.Parse("0")), 
      Data); } 
    } 
} 
+0

Là một câu hỏi khá đơn giản suy nghĩ đầu tiên của tôi là đây là một số loại bài tập về nhà hoặc câu hỏi phỏng vấn xin việc - không nhất thiết phải xem xét trước khi đăng câu trả lời đầy đủ về mã nguồn cho một vấn đề dễ dàng. –

+1

Hey Bill K, nó đã xảy ra với tôi, nhưng nó đã được viết tốt và lịch sự vì vậy đối với tôi nó khá đơn giản; mọi người đăng câu hỏi, nếu bạn muốn trả lời, hãy làm như vậy, nếu bạn muốn bỏ phiếu bầu, hãy đặt câu hỏi, chọc vào nó hoặc thậm chí bỏ qua nó, bạn có thể làm tất cả những điều đó. Bạn cũng có thể khiếu nại khi có người khác trả lời. Tự do, bạn phải yêu nó. –

+0

Vâng, tôi đồng ý - Do đó tôi chỉ nhắc nhở mọi người một cách nhẹ nhàng rằng cung cấp các câu trả lời hoàn chỉnh cho các câu hỏi đơn giản mà bạn có thể làm không ai ngoài chính bản thân bạn. –

1

Cho đến nay như chèn mục mới giữa những người nhất định đi, tôi sẽ tư vấn cho đọc trong file văn bản vào dòng tách và sau đó lưu trữ chúng trong List. Bằng cách đó, bạn có thể sử dụng phương thức Insert(...) để chèn các dòng mới của mình. Từ đó, bạn có thể viết lại dòng vào tệp.

Khi đọc các dòng, bạn có thể sử dụng một trong các phương thức trợ giúp tĩnh trong lớp System.IO.File: ReadAllTextReadAllLines.

Lưu ý: Tôi đã thêm liên kết đến Tài liệu MSDN cho từng phương pháp và lớp tôi đã đề cập, vì bạn đã nói bạn mới sử dụng C# và lập trình nói chung.

+1

Có hàng triệu dòng, không chắc chắn lưu trữ toàn bộ tệp trong bộ nhớ là một ý tưởng hay. –

+0

Nếu anh ta đang đọc hàng triệu dòng có thể hơi khó chịu, đặc biệt là từ khi tìm thấy một dòng thiếu, anh ta chỉ cần hai dòng trong bộ nhớ tại một thời điểm - Hiện tại và Trước đó. – asawyer

+0

Cả hai bình luận đều đúng - đây chỉ là một gợi ý. Bất kỳ giải pháp thực tế nào sẽ phụ thuộc hoàn toàn vào việc triển khai. Dù bằng cách nào, câu trả lời sẽ dẫn anh ta tìm một giải pháp phù hợp với anh ta. –

1
String prevTime; 
String prevData; 

while(String line = myStreamReader.ReadLine()) 
{ 
    String[] parts = line.Split(new Char[] { ' ' }); 
    String time = parts[0]; 
    String data = parts[1]; 

    Int32 iPrevTime = Int32.Parse(prevTime); 
    Int32 iCurrentTime = Int32.Parse(time); 

    // May need to loop here if you're missing more than one second 
    if(iCurrentTime > iPrevTime + 1) 
      AddData((iPrevTime + 1).ToString(), prevData); 

    AddData(time, data); 
    prevTime = time; 
    prevData = data; 
} 

Đây là một số mã giả để giúp bạn bắt đầu. Tôi nghĩ bạn sẽ muốn loại thuật toán này.

+0

Cảm ơn bạn đã viết bài này, tôi sẽ đọc về những gì nó làm và xem nó có thực hiện được không. –

4

Có một vài điều bạn cần đặt cùng nhau.

  1. Đọc một line-by-line file: Xem ở đây: Reading a Text File One Line at a Time
  2. Viết một line-by-line file: StreamWriter.WriteLine
  3. Theo dõi các dòng đọc qua. (Chỉ cần sử dụng một biến trong vòng lặp while của bạn, nơi bạn đọc các dòng)
  4. Kiểm tra xem có lỗ hổng hay không. Có thể bằng cách phân tích cú pháp cột đầu tiên (string.Split) bằng cách sử dụng TimeSpan.Parse. Nếu có một khoảng trống sau đó viết dòng đọc cuối cùng, tăng khoảng thời gian.
+0

Cảm ơn, tôi nghĩ rằng tôi có một nắm bắt trên 1-3, nhưng # 4 là hoàn toàn mới với tôi vì vậy tôi sẽ bắt đầu đọc về string.Split và TimeSpan.Parse. –

3

Trong adition cho tất cả các câu trả lời, xem xét rằng bạn đang nói về một tập tin rất lớn, nên dùng mặt MemoryMappedFiles, có thể đọc here để xem làm thế nào để sử dụng chúng từ C#.

Đây là không hoạt động cải thiện, nhưng cải thiện bộ nhớ là chắc chắn.

1

Điều này giả định thời gian không bao giờ cách nhau hơn một giây. Nếu giả định đó là sai, nó đủ dễ dàng để sửa đổi bên dưới để nó viết lastValue trong một vòng lặp cho mỗi giây mất tích. Cập nhật Tôi đã bỏ lỡ ví dụ của bạn rằng thực tế nó có thể bỏ lỡ nhiều giây. Tôi đã thay đổi ví dụ dưới đây để giải quyết vấn đề đó.

using (StreamReader reader = OpenYourInputFile()) 
using (StreamWriter writer = OpenYourOutputFile()) 
{ 
    TimeSpan? lastTime; 
    TimeSpan currentTime, maxDiff = TimeSpan.FromSeconds(1); 
    string lastValue, currentline, currentValue, format = "{0:hhmmss} {1}"; 

    while((currentLine = reader.ReadLine()) != null) 
    { 
     string[] s = currentLine.Split(' '); 
     currentTime = DateTime.ParseExact("hhmmss", s[0] CultureInfo.InvariantCulture).TimeOfDay; 
     currentValue = s[1]; 

     if (lastTime.HasValue && currentTime - lastTime.Value > maxDiff) 
     { 
     for(int x = 1; x <= (currentTime - lastTime).Seconds; x++) writer.WriteLine(string.Format(format, DateTime.Today.Add(lastTime).AddSeconds(x), lastValue); 
     } 

     writer.WriteLine(string.Format(format, DateTime.Today.Add(currentTime), currentValue); 

     lastTime = currentTime; 
     lastValue = currentValue; 
    } 

} 
+0

Cảm ơn rất nhiều! Tôi sẽ đọc về điều này và sau đó thử nó. –

1

Dưới đây là một số mã thô cho bạn. Tôi không xử lý đúng cách mọi thứ, nó chỉ để giúp bạn bắt đầu.

 DateTime lastTime; 
     string lastValue = null; 
     StreamReader reader = File.OpenText("path"); 
     StreamWriter writer = new StreamWriter(File.OpenWrite("newPath")); 

     while (!reader.EndOfStream) 
     { 
      string[] lineData = reader.ReadLine().Split(' '); 
      DateTime currentTime = DateTime.Parse(lineData[0]); 
      string value = lineData[1]; 

      if (lastValue != null) 
      { 
       while (lastTime < currentTime.AddSeconds(-1)) 
       { 
        lastTime = lastTime.AddSeconds(1); 
        writer.WriteLine("{0} {1}", lastTime, lastValue); 
       } 
      } 
      writer.WriteLine("{0} {1}", currentTime, value); 
      lastTime = currentTime; 
      lastValue = value; 
     } 
1
 string line;//The line that is read. 
     string previousLine = "0 0"; 
     int prevTime = 0; 

     //These "using"'s are so that the resources they use will be freed when the block (i.e. {}) is finished. 
     using (System.IO.StreamReader originalFile = new System.IO.StreamReader("c:\\users\\Me\\t.txt")) 
     using (System.IO.StreamWriter newFile = new System.IO.StreamWriter("c:\\users\\Me\\t2.txt")) 
     { 
      while ((line = originalFile.ReadLine()) != null) 
      { 
       //"Split" changes the words in "line" (- that are separated by a space) to an array. 
       //"Parse" takes the first in that array (by using "[0]") and changes it into an integer. 
       int time = int.Parse(line.Split(' ')[0]); 
       while (prevTime != 0 && time > ++prevTime) newFile.WriteLine(prevTime.ToString() + " " + previousLine.Split(' ')[1]); 

       previousLine = line; 
       prevTime = time; 
       newFile.WriteLine(line); 
      } 
     } 
Các vấn đề liên quan