簡體   English   中英

笛卡爾積或 2 個大文本文件的最佳方法

[英]Best approach for Cartesian product or 2 large text files

我想將 2 個大文本文件合並在一起並使用 2 個輸入文件的笛卡爾積生成新文件時遇到問題。 我確實知道代碼的外觀,但不確定用哪種語言來構建這樣的實用程序。 我有 Windows 服務器,並且熟悉 C#、Shell 腳本。

注意:File1 可以是大約 20 MB,File2 可以包含大約 6000 條記錄。 所以我想要實現的是在新文件中復制 20MB 數據 6000 次。

以下是我的文件外觀的較小示例

文件 1

Head-A-AA-AAA
Child-A1-AA1-AAA1
Child-A2-AA2-AAA2
Child-A3-AA3-AAA3
Head-B-BB-BBB
Child-B1-BB1-BBB1
Child-B2-BB2-BBB2
Child-B3-BB3-BBB3

文件 2

Store1
Store2
Store3

預期輸出文件

Store1
Head-A-AA-AAA
Child-A1-AA1-AAA1
Child-A2-AA2-AAA2
Child-A3-AA3-AAA3
Head-B-BB-BBB
Child-B1-BB1-BBB1
Child-B2-BB2-BBB2
Child-B3-BB3-BBB3
Store2
Head-A-AA-AAA
Child-A1-AA1-AAA1
Child-A2-AA2-AAA2
Child-A3-AA3-AAA3
Head-B-BB-BBB
Child-B1-BB1-BBB1
Child-B2-BB2-BBB2
Child-B3-BB3-BBB3
Store3
Head-A-AA-AAA
Child-A1-AA1-AAA1
Child-A2-AA2-AAA2
Child-A3-AA3-AAA3
Head-B-BB-BBB
Child-B1-BB1-BBB1
Child-B2-BB2-BBB2
Child-B3-BB3-BBB3

尋找帶有 Windows 服務的 C# 代碼是否有用或者我需要使用任何其他工具/實用程序/腳本的建議?

編輯:在 c# 代碼下創建。 但是生成 150 GB 的輸出文件需要幾個小時。 我正在尋找更快的方法。 我正在從文件 1 中獲取內容並為第二個文件中的每個記錄復制它

FileInfo[] fi;
            List<FileInfo> TodaysFiles = new List<FileInfo>();
            string PublishId;
            DirectoryInfo di = new DirectoryInfo(@"\\InputPath");

            fi = di.GetFiles().Where(file => file.FullName.Contains("TRANSMIT_MASS")).ToArray();

            foreach (FileInfo f in fi)
            {
                string[] tokens = f.Name.Split('_');
                if(tokens[2] == DateTime.Now.AddDays(1).ToString("MMddyyyy"))
                {
                    PublishId = tokens[0];
                    string MACSFile = @"\\OutputPath\\" + PublishId + ".txt";
                    string path =f.FullName;

                    string StoreFile = di.GetFiles().Where(file => file.Name.StartsWith(PublishId) && file.Name.Contains("SUBS")).Single().FullName;

                    using (FileStream fs = File.Open(StoreFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    using (BufferedStream bs = new BufferedStream(fs))
                    using (StreamReader sr = new StreamReader(bs))
                    {
                        using (StreamWriter outfile = new StreamWriter(MACSFile))
                        {
                            String StoreNumber;
                            while ((StoreNumber = sr.ReadLine()) != null)
                            {
                                Console.WriteLine(StoreNumber);
                                if (StoreNumber.Length > 5)
                                {
                                    using (FileStream fsProfile = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                                    using (BufferedStream bsProfile = new BufferedStream(fsProfile))
                                    using (StreamReader srProfile = new StreamReader(bsProfile))
                                    {
                                        outfile.WriteLine(srProfile.ReadToEnd().TrimEnd());
                                        
                                    }

                                }

                            }
                        }
                    }

                }
            }

你提到了shell腳本。 這是一個工作外殼示例:

while read line; do
  echo "$line" >> Output
  cat File1 >> Output
done < File2

這里File2的行被循環並與整個File1寫入任意輸出文件Output

通過將其保存在本地文件something.sh並運行sh something.sh輕松運行。

我們可以以內存為代價進一步優化代碼的性能。 全部重構它以使其更干凈。

文件 1:6000 行

文件 2 : 20Mb

作為文件 1,(較小的文件)只包含幾行,會將整個文件讀入內存並循環遍歷它。

foreach (string line in File.ReadAllLines(File1))

如果您還有內存容量,您也可以將整個第二個文件讀入內存

var file2 = File.ReadAllText(File2)

現在您要做的就是將所有內容附加到第三個文件中。 由於大小,我們不會將其存儲在內存中。

所以整個代碼將是

var file2 = File.ReadAllText(File2);
var destinationFile = "destination/file/path";

foreach (string line in File.ReadAllLines(File1)){
File.AppendAllText(destinationFile, line);
File.AppendAllText(destinationFile, file2);
}

進一步優化:跳過以保持代碼簡單

File.AppendAllText 被調用了兩次,因為我們不想在代碼中做 line + file2。 它將分配更多的內存。

要進一步優化,您可以使用 StringBuilder,將 file2 加載到其中。

var file2 = new StringBuilder(File.ReadAllText(File2));

並對其進行變異。 這應該可以防止對 File.AppendAllText 的 2 次調用並提供更高的性能。

很難減少 I/O 時間。 您可以嘗試使用大量讀/寫的情況(我認為它更有效,因為 I/O 操作需要分配/釋放操作系統的資源)。 因此,如果您閱讀所有內容,將結果匯總到內存中,然后寫入文件,那么它將在 I/O 上花費更少的時間。 內存操作可以達到更高的速度,因為與 IO 操作相比,RAM 和處理器操作的處理速度非常快。

  1. 文件 1 - 很小 - 讀取一次並將結果保存在內存中。
  2. 文件 2 - 很大 - 分塊讀取。 例如,您可以使用 streamReader.ReadLine() N 次
  3. 如果可能,將第一個文件的內存數據與第二個文件的每個塊並行合並。
  4. 輸出 - 僅打開/關閉流一次,在處理每個卡盤后寫入。

PS:這里不需要緩沖流,因為文件流已經被緩沖了。 緩沖流對於網絡 IO 操作很有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM