簡體   English   中英

讀取JSON文件中的百萬個字符時發生異常[OutOfMemoryException]

[英]Exception when reading million characters in JSON file [OutOfMemoryException]

我已經下載了從Azure Blob存儲記錄的JSON文件。 檔案大小為137MB。

如下圖所示,使用Notepad ++打開時的字符和行屬性: 在此處輸入圖片說明

從文件上下文菜單中選擇“使用Notepad ++編輯”大約需要1-2秒。 因此,我決定創建一個程序以將JSON轉換器轉換為CSV文件格式。 但似乎,我遇到了某種例外。 當前,對於查看JSON內容,我將在RichTextBox中顯示,因為它可以在決定轉換為CSV之前查看內容。

事件開始加載:-

private async void txtjsonname_DoubleClick(object sender, EventArgs e)
{
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.Filter = "JSON Files (*.json)|*.json";
    ofd.InitialDirectory = @"C:\";
    ofd.Title = "Select single json file to be converted";
    ofd.Multiselect = false;
    if (ofd.ShowDialog() == DialogResult.OK)
    {
        rtbstat.Text = null;
        txtcsvname.Text = null;
        txtjsonname.Text = null;
        lblcsvpath.Text = null;
        lbljsonpath.Text = null;
        rtbjson.Clear();
        txtjsonname.Text = Path.GetFileName(ofd.FileName);
        lbljsonpath.Text = Path.GetDirectoryName(ofd.FileName);

        if (await LoadJSONtoRTB(ofd.FileName))
        {
            rtbjson.WordWrap = false;
            rtbstat.Text = "Load file finished! " + (rtbjson.Lines.Count()).ToString() + " line(s) detected | " + rtbjson.Text.Length.ToString() + " character(s) detected";
            txtcsvname.Text = Path.GetFileNameWithoutExtension(ofd.FileName) + ".csv";
        }
    }
    await Task.Delay(1000);
}

我嘗試過並遇到異常的代碼:-

第一種方法:第一個代碼:

private async Task<bool> LoadJSONtoRTB(string path)
    {
        try
        {
            foreach (var line in File.ReadLines(path))
            {
                rtbjson.Text = line;
            }
            await Task.Delay(10);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

第二個代碼:

private async Task<bool> LoadJSONtoRTB(string path)
    {
        try
        {
            using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            using (BufferedStream bs = new BufferedStream(fs))
            using (StreamReader sr = new StreamReader(bs))
            {
                string line;
                while ((line = sr.ReadLine()) != null)
                {
                    rtbjson.AppendText(line);
                }
            }
            await Task.Delay(10);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

在此處輸入圖片說明 異常:System.Windows.Forms.dll中發生了類型為'System.AccessViolationException'的未處理異常

附加信息:嘗試讀取或寫入受保護的內存。 這通常表明其他內存已損壞。

第二種方法:

private async Task<bool> LoadJSONtoRTB(string path)
{
    try
    {
        StreamReader sr = new StreamReader(@path);
        while (!sr.EndOfStream)
            rtbjson.Text += sr.ReadLine();
        await Task.Delay(10);
        return true;
    }
    catch (Exception)
    {
        return false;
    }
}

使用上面的代碼,當我放置斷點以查看進度時,它將運行約12分鍾。 在此處輸入圖片說明

12分鍾,讀取長度為600萬。

有什么方法可以顯示文本文件(json / txt),其示例為6400萬個字符的長度,例如notepad ++只需1-2秒即可查看該文件?

我懷疑Notepad ++會將整個文件加載到內存中,該文件等於System.IO.File.ReadAllText 同樣,將文件的每一行附加到字符串上也沒有任何好處,最終結果是占用了相同的內存。 使用RichTextBox,您可以做的最好的事情是:

richTextBox1.Text = System.IO.File.ReadAllText(filePath);

無論如何,Notepad ++使用的Scintilla比RichTextBox快。

您可以嘗試使用ScintillaNET ,它是Scintilla的包裝。

您可以使用與RichTextBox相同的方式來設置控件文本:

scintilla1.Text = System.IO.File.ReadAllText(filePath);

您的LoadJSONtoRTB方法異步運行。 因此,您正在嘗試從錯誤的線程更新gui(文本框)。 這種方法將幫助您在正確的線程上運行gui更新:

this.Invoke(new Action(() => { rtbjson.Text += sr.ReadLine(); }));

當然,還有更有效的方法,例如StringBuilder來填充大量文本。 重要的收獲是始終在gui線程上更新gui。 這可以通過運行Form.Invoke來完成

暫無
暫無

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

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