2

So, I have a text file with thousands of lines formatted similarly to this:

123456:0.8525000:1590882780:91011

These files are almost always a different length, and I only need to read the first two parts of the line, being 123456:0.8525000.

I know that I can split each line using C#, but I'm unsure how to only read the first 2 parts. Anyone have any idea on how to do this? Sorry if my question doesn't make sense, I can restate it if needed.

thedogger
  • 33
  • 5
  • When you say "only read the first 2 parts," are you trying to optimize some aspect of the file read? At a low level, each byte of the file will have to be scanned in order to find the EOL markers. To put more directly: why is splitting not working for you? – Paul Keister May 31 '20 at 00:24
  • If the file lines are always fixed width or the part you need to extract is always 16 chars, do a `substing`, which will be quicker for large files – Supun De Silva May 31 '20 at 00:25
  • Does this answer your question? [To get specific part of a string in c#](https://stackoverflow.com/questions/6578254/to-get-specific-part-of-a-string-in-c-sharp) – Pavel Anikhouski May 31 '20 at 09:15

3 Answers3

2

The Split function returns a string[], an array of strings.

Just take the 2 first elements of the result of Split (with : as the separator).

    var read = "123456:0.8525000:1590882780:91011";
    var values = read.Split(":");
    Console.WriteLine(values[0]); // 123456
    Console.WriteLine(values[1]); // 0.8525000

.NET Fiddle

Don't forget that elements of values are string and not yet int or double values. See How to convert string to integer in C# for how to convert from string to number type.

Pac0
  • 21,465
  • 8
  • 65
  • 74
1

There are TONS of ways to doing this but I am going to suggest some options that involving read the full line as its much easier to work with / understand and that your lines are of varying length. I did add a suggestion on using StreamReader on a file at the end in addendum but you may need to figure out serious work arounds on skipping lines you don't want, restarting a char iterating loop on new lines etc.

I first demonstrate the latest and greatest IAsyncEnumerable found in NetCore 3.x followed by a similar string-based approach. By sharing an Int example that is a slightly advanced and that will also be asynchronous, I hope to also help others and demonstrate a fairly modern approach in 2020. Streaming out only the data you need will be a huge benefit in keeping it fast and a low memory footprint.

public static async IAsyncEnumerable<int> StreamFileOutAsIntsAsync(string filePathName)
{
    if (string.IsNullOrWhiteSpace(filePathName)) throw new ArgumentNullException(nameof(filePathName));
    if (!File.Exists(filePathName)) throw new ArgumentException($"{filePathName} is not a valid file path.");

    using var streamReader = File.OpenText(filePathName);
    string currentLine;

    while ((currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false)) != null)
    {
        if (int.TryParse(currentLine.AsSpan(), out var output))
        {
            yield return output;
        }
    }
}

This streams every int out of a file, checking that file exists and that the filename path is not null or blank etc.

Streaming maybe too much for a beginner so I don't know your level.

You may want to start with just turning the file into a list of strings.

Modifying my previous example above to something less complex but split your strings for you. I recommend learning about streaming so you don't have every piece of string in memory while you work on it... or maybe you want them all. I am not here to judge.

Once you get your string line out from a file you can do whatever else needs to be done.

public static async Task<List<string>> GetStringsFromFileAsync(string filePathName)
{
    if (string.IsNullOrWhiteSpace(filePathName)) throw new ArgumentNullException(nameof(filePathName));
    if (!File.Exists(filePathName)) throw new ArgumentException($"{filePathName} is not a valid file path.");

    using var streamReader = File.OpenText(filePathName);

    string currentLine;
    var strings = new List<string>();

    while ((currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false)) != null)
    {
        var lineAsArray = currentLine.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries);

        // Simple Data Validation
        if (lineAsArray.Length == 4)
        {
            strings.Add($"{lineAsArray[0]}:{lineAsArray[1]}");
            strings.Add($"{lineAsArray[2]}:{lineAsArray[3]}");
        }
    }

    return strings;
}

The meat of the code is really simple, open the file for reading!

using var streamReader = File.OpenText(filePathName);

and then loop through that file...

while ((currentLine = await streamReader.ReadLineAsync()) != null)
{
    var lineAsArray = currentLine.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries);

    // Simple Data Validation
    if (lineAsArray.Length == 4)
    {
        // Do whatever you need to do with the first bits of information.
        // In this case, we add them all to a list for return.
        strings.Add($"{lineAsArray[0]}:{lineAsArray[1]}");
        strings.Add($"{lineAsArray[2]}:{lineAsArray[3]}");
    }
}

What this demonstrates is that, for every line that I read out that is not null, break into four parts (based on the ":") character removing all empty entries.

We then use a C# feature called String Interpolation ($"") to put the first two back together with ":" as a string. Then the second two. Or whatever you need to do with reading each part of the line.

That's really all there is to it! Hope it helps.

Addendum: If you really need to read parts of file, please use a StreamReader.Read and Peek()

using (var sr = new StreamReader(path))
{
    while (sr.Peek() >= 0)
    {
        Console.Write((char)sr.Read());
    }
}

Reading each character

HouseCat
  • 1,559
  • 20
  • 22
0

Some bare bones code:

string fileName = @"c:\some folder\path\file.txt";
using (StreamReader sr = new StreamReader(fileName))
{
    while (!sr.EndOfStream)
    {
        String[] values = sr.ReadLine().Split(":".ToCharArray());
        if (values.Length >= 2)
        {
            // ... do something with values[0] and values[1] ...
            Console.WriteLine(values[0] + ", " + values[1]);
        }
    }
}
Idle_Mind
  • 38,363
  • 3
  • 29
  • 40