Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest way to split a huge text into smaller chunks

Tags:

substring

c#

.net

I have used the below code to split the string, but it takes a lot of time.

using (StreamReader srSegmentData = new StreamReader(fileNamePath))
{
    string strSegmentData = "";
    string line = srSegmentData.ReadToEnd();
    int startPos = 0;

    ArrayList alSegments = new ArrayList();
    while (startPos < line.Length && (line.Length - startPos) >= segmentSize)
    {
        strSegmentData = strSegmentData + line.Substring(startPos, segmentSize) + Environment.NewLine;
        alSegments.Add(line.Substring(startPos, segmentSize) + Environment.NewLine);
        startPos = startPos + segmentSize;
    }
}

Please suggest me an alternative way to split the string into smaller chunks of fixed size

like image 351
Shankar Anumula Avatar asked Dec 23 '15 07:12

Shankar Anumula


People also ask

How do I break a large text file into smaller parts?

To split a file into pieces, you simply use the split command. By default, the split command uses a very simple naming scheme. The file chunks will be named xaa, xab, xac, etc., and, presumably, if you break up a file that is sufficiently large, you might even get chunks named xza and xzz.

How do I split a large file into multiple smaller pieces in Linux?

To split large files into small pieces, we use the split command in the Linux operating system. The split command is used to split or break large files into small pieces in the Linux system. By default, it generates output files of a fixed size, the default lines are 1000 and the default prefix would be 'x'.

How do you split a large file into smaller parts in Python?

To split a big binary file in multiple files, you should first read the file by the size of chunk you want to create, then write that chunk to a file, read the next chunk and repeat until you reach the end of original file.


1 Answers

First of all you should define what you mean with chunk size. If you mean chunks with a fixed number of code units then your actual algorithm may be slow but it works. If it's not what you intend and you actually mean chunks with a fixed number of characters then it's broken. I discussed a similar issue in this Code Review post: Split a string into chunks of the same length then I will repeat here only relevant parts.

  • You're partitioning over Char but String is UTF-16 encoded then you may produce broken strings in, at least, three cases:

    1. One character is encoded with more than one code unit. Unicode code point for that character is encoded as two UTF-16 code units, each code unit may end up in two different slices (and both strings will be invalid).
    2. One character is composed by more than one code point. You're dealing with a character made by two separate Unicode code points (for example Han character 𠀑).
    3. One character has combining characters or modifiers. This is more common than you may think: for example Unicode combining character like U+0300 COMBINING GRAVE ACCENT used to build à and Unicode modifiers such as U+02BC MODIFIER LETTER APOSTROPHE.
  • Definition of character for a programming language and for a human being are pretty different, for example in Slovak is a single character however it's made by 2/3 Unicode code points which are in this case also 2/3 UTF-16 code units then "dž".Length > 1. More about this and other cultural issues on How can I perform a Unicode aware character by character comparison?.
  • Ligatures exist. Assuming one ligature is one code point (and also assuming it's encoded as one code unit) then you will treat it as a single glyph however it represents two characters. What to do in this case? In general definition of character may be pretty vague because it has a different meaning according to discipline where this word is used. You can't (probably) handle everything correctly but you should set some constraints and document code behavior.

One proposed (and untested) implementation may be this:

public static IEnumerable<string> Split(this string value, int desiredLength)
{
    var characters = StringInfo.GetTextElementEnumerator(value);
    while (characters.MoveNext())
        yield return String.Concat(Take(characters, desiredLength));
}

private static IEnumerable<string> Take(TextElementEnumerator enumerator, int count)
{
    for (int i = 0; i < count; ++i)
    {
        yield return (string)enumerator.Current;

        if (!enumerator.MoveNext())
            yield break;
    }
}

It's not optimized for speed (as you can see I tried to keep code short and clear using enumerations) but, for big files, it still perform better than your implementation (see next paragraph for the reason).

About your code note that:

  • You're building a huge ArrayList (?!) to hold result. Also note that in this way you resize ArrayList multiple times (even if, given input size and chunk size then its final size is known).
  • strSegmentData is rebuilt multiple times, if you need to accumulate characters you must use StringBuilder otherwise each operation will allocate a new string and copying old value (it's slow and it also adds pressure to Garbage Collector).

There are faster implementations (see linked Code Review post, especially Heslacher's implementation for a much faster version) and if you do not need to handle Unicode correctly (you're sure you manage only US ASCII characters) then there is also a pretty readable implementation from Jon Skeet (note that, after profiling your code, you may still improve its performance for big files pre-allocating right size output list). I do not repeat their code here then please refer to linked posts.

In your specific you do not need to read entire huge file in memory, you can read/parse n characters at time (don't worry too much about disk access, I/O is buffered). It will slightly degrade performance but it will greatly improve memory usage. Alternatively you can read line by line (managing to handle cross-line chunks).

like image 115
Adriano Repetti Avatar answered Sep 20 '22 12:09

Adriano Repetti