簡體   English   中英

C#StringBuilder版本,允許大於20億個字符的字符串

[英]Version of C# StringBuilder to allow for strings larger than 2 billion characters

在C#中, 64位Windows + .NET 4.5(或更高版本) + 在App.config文件中啟用gcAllowVeryLargeObjects允許對象大於2 GB。 太酷了,但是不幸的是,C#允許字符數組中的最大元素數量仍然限制為2 ^ 31 = 21.5億個字符 測試證實了這一點。

為了克服這個問題,Microsoft 建議在選項B中本機創建數組(它們的“選項C”甚至不編譯)。 這很適合我,因為速度也是一個問題。 是否有一些經過嘗試和信任的.NET不安全/本機/互操作/ PInvoke代碼可以替換並用作增強的StringBuilder來解決20億個元素限制的問題?

最好使用不安全/拼湊的代碼,但不要破壞交易。 另外,是否有可用的.NET(安全)版本?

理想情況下,替換StringBuilder時應先小(最好由用戶定義),然后在每次超過容量時,將其大小重復增加一倍。 我主要是在這里尋找append()功能。 將字符串保存到文件中也很有用,盡管我確信如果還合並了substring()功能,我可以對該位進行編程。 如果代碼使用pinvoke,則顯然必須考慮某種程度的內存管理,以避免內存丟失。

如果已經存在一些簡單的代碼,我不想重新創建輪子,但是,另一方面,我不想僅為該簡單功能下載並合並DLL。

我還使用.NET 3.5來迎合沒有最新版本Windows的用戶。

根據此答案 ,C ++中字符串的大小不受限制。

您可以用C ++編寫字符串處理代碼,並使用DLL導入在C#代碼和C ++代碼之間進行通信。 這使得從C#代碼調用C ++函數變得簡單。

在大字符串上進行處理的代碼部分將規定C ++和C#代碼之間的邊界位置。 顯然,任何對大字符串的引用都需要保留在C ++一側,但是隨后可以將匯總處理結果信息傳遞回C#代碼。

是代碼項目頁面的鏈接,該頁面提供了有關C#到C ++ DLL導入的一些指導。

因此,最后我最終創建了自己的BigStringBuilder函數。 這是一個列表,其中每個列表元素(或頁面)都是一個char數組(類型為List<char[]> )。

只要您使用的是64位Windows,您現在就可以輕松超過20億個字符元素限制。 我設法測試創建了一個大約32 GB的巨型字符串(需要首先在OS中增加虛擬內存,否則我在8GB RAM PC上只能得到7GB)。 我確信它可以輕松處理超過32GB的數據。 從理論上講,它應該能夠處理大約1,000,000,000 * 1,000,000,000個字符或一個五百萬個字符,這對於任何人來說都足夠了。

在速度方面,一些快速測試表明,追加時它僅比StringBuilder慢33%。 如果我選擇2D鋸齒狀char數組( char[][]而不是List<char[]> ,則可以獲得非常相似的性能,但是List更易於使用,因此我堅持使用它。

希望其他人發現它有用! 可能存在錯誤,因此請謹慎使用。 我雖然測試得很好。

// A simplified version specially for StackOverflow
public class BigStringBuilder
{
    List<char[]> c = new List<char[]>();
    private int pagedepth;
    private long pagesize;
    private long mpagesize;         // https://stackoverflow.com/questions/11040646/faster-modulus-in-c-c
    private int currentPage = 0;
    private int currentPosInPage = 0;

    public BigStringBuilder(int pagedepth = 12) {   // pagesize is 2^pagedepth (since must be a power of 2 for a fast indexer)
        this.pagedepth = pagedepth;
        pagesize = (long)Math.Pow(2, pagedepth);
        mpagesize = pagesize - 1;
        c.Add(new char[pagesize]);
    }

    // Indexer for this class, so you can use convenient square bracket indexing to address char elements within the array!!
    public char this[long n]    {
        get { return c[(int)(n >> pagedepth)][n & mpagesize]; }
        set { c[(int)(n >> pagedepth)][n & mpagesize] = value; }
    }

    public string[] returnPagesForTestingPurposes() {
        string[] s = new string[currentPage + 1];
        for (int i = 0; i < currentPage + 1; i++) s[i] = new string(c[i]);
        return s;
    }
    public void clear() {
        c = new List<char[]>();
        c.Add(new char[pagesize]);
        currentPage = 0;
        currentPosInPage = 0;
    }


    public void fileOpen(string path)
    {
        clear();
        StreamReader sw = new StreamReader(path);
        int len = 0;
        while ((len = sw.ReadBlock(c[currentPage], 0, (int)pagesize)) != 0) {
            if (!sw.EndOfStream)    {
                currentPage++;
                if (currentPage > (c.Count - 1)) c.Add(new char[pagesize]);
            }
            else    {
                currentPosInPage = len;
                break;
            }
        }
        sw.Close();
    }

    // See: https://stackoverflow.com/questions/373365/how-do-i-write-out-a-text-file-in-c-sharp-with-a-code-page-other-than-utf-8/373372
    public void fileSave(string path)   {
        StreamWriter sw = File.CreateText(path);
        for (int i = 0; i < currentPage; i++) sw.Write(new string(c[i]));
        sw.Write(new string(c[currentPage], 0, currentPosInPage));
        sw.Close();
    }

    public long length()    {
        return (long)currentPage * (long)pagesize + (long)currentPosInPage;
    }

    public string ToString(long max = 2000000000)   {
        if (length() < max) return substring(0, length());
        else return substring(0, max);
    }

    public string substring(long x, long y) {
        StringBuilder sb = new StringBuilder();
        for (long n = x; n < y; n++) sb.Append(c[(int)(n >> pagedepth)][n & mpagesize]);    //8s
        return sb.ToString();
    }

    public bool match(string find, long start = 0)  {
        //if (s.Length > length()) return false;
        for (int i = 0; i < find.Length; i++) if (i + start == find.Length || this[start + i] != find[i]) return false;
        return true;
    }
    public void replace(string s, long pos) {
        for (int i = 0; i < s.Length; i++)  {
            c[(int)(pos >> pagedepth)][pos & mpagesize] = s[i];
            pos++;
        }
    }

    public void Append(string s)
    {
        for (int i = 0; i < s.Length; i++)
        {
            c[currentPage][currentPosInPage] = s[i];
            currentPosInPage++;
            if (currentPosInPage == pagesize)
            {
                currentPosInPage = 0;
                currentPage++;
                if (currentPage == c.Count) c.Add(new char[pagesize]);
            }
        }
    }


}

暫無
暫無

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

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