Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
813 views
in Technique[技术] by (71.8m points)

parsing - How to read into memory the lines of a text file from an IFormFile in ASP.NET Core?

Say you have this Action:

public List<string> Index(IFormFile file){

    //extract list of strings from the file
    return new List<string>();
}

I've found plenty of examples of saving the file to the drive, but what if I instead want to skip this and just read the lines of text into an array in memory, directly from the IFormFile?

question from:https://stackoverflow.com/questions/40045147/how-to-read-into-memory-the-lines-of-a-text-file-from-an-iformfile-in-asp-net-co

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The abstraction for the IFormFile has an .OpenReadStream method. To prevent a ton of undesirable and potentially large allocations, we should read a single line at a time and build up our list from each line that we read. Additionally, we could encapsulate this logic in an extension method. The Index action ends up looking like this:

public List<string> Index(IFormFile file) => file.ReadAsList();

The corresponding extension method looks like this:

public static List<string> ReadAsList(this IFormFile file)
{
    var result = new StringBuilder();
    using (var reader = new StreamReader(file.OpenReadStream()))
    {
        while (reader.Peek() >= 0)
            result.AppendLine(reader.ReadLine()); 
    }
    return result;
}

Likewise you could have an async version as well:

public static async Task<string> ReadAsStringAsync(this IFormFile file)
{
    var result = new StringBuilder();
    using (var reader = new StreamReader(file.OpenReadStream()))
    {
        while (reader.Peek() >= 0)
            result.AppendLine(await reader.ReadLineAsync()); 
    }
    return result.ToString();
}

Alternatively, you could you use an ObjectPool<StringBuilder> and modern C# 8 features.

public static async Task<string> ReadAsStringAsync(
    this IFormFile file, Object<StringBuilder> pool)
{
    var builder = pool.Get();
    try
    {
        using var reader = new StreamReader(file.OpenReadStream());
        while (reader.Peek() >= 0)
        {
            builder.AppendLine(await reader.ReadLineAsync()); 
        }
        return builder.ToString();
    }
    finally
    {
        pool.Return(builder);
    }
}

Then you could use this version this way:

public Task<List<string>> Index(
    IFormFile file, [FromServices] ObjectPool<StringBuilder> pool) =>
    file.ReadAsListAsync(pool);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...