关于c#:如何上传csv文件并解析它?

How upload csv file and parse it?

我需要上传csv文件并解析它。我可以在HTTP主体请求中看到文件,但是当我在CSVReader中传递它时,我可以看到base64字符串状的头文件:enter image description here

在客户端,我使用AngularJS:

1
2
3
4
5
6
7
8
'uploadBulkUsersFile': {
                method: 'POST', url: CONFIG.apiServiceBaseUri +"api/users/bulkUsers",
                headers: {
                    "Content-Type": undefined
                },
                transformRequest: angular.identity,
                withCredentials: true
            },

并致电:

1
2
3
4
5
6
7
8
var _uploadBulkUsersFile = function (bulkUsersFile) {
    var fd = new FormData();
    fd.append("file", bulkUsersFile);

    return usersResource.uploadBulkUsersFile({}, fd, function (result) {
        return result;
    }).$promise;
};

在服务器端,我使用WebAPI2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    if (!Request.Content.IsMimeMultipartContent())
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);

    var provider = new MultipartMemoryStreamProvider();
    await Request.Content.ReadAsMultipartAsync(provider);
    foreach (var file in provider.Contents)
    {
        var buffer = await file.ReadAsStreamAsync();

        TextReader textReader = new StreamReader(buffer);
        var csv = new CsvReader(textReader);
        var records = csv.GetRecords<BulkUploadUser>().ToList();

        return Created("DefaultApi", records);
    }

HTTP请求负载

------webkitformboundaryskplgjrinomnpxvp(webkitformboundaryskplgjrinomnpxvp)内容处置:表单数据;name="file"

1
2
data:application/vnd.ms-excel;base64,RW1haWwsRmlyc3ROYW1lLExhc3ROYW1lDQpwcm9zdG8uZHVkYUBnbWFpbC5jb20yLERlbmlzLER1ZGFpZXYNCnByb3N0by5kdWRhQGdtYWlsLmNvbSxEZW5pcyxEdWRhaWV2DQpwcm9zdG8uZHVkYUBnbWFpbC5jb20yLERlbmlzLER1ZGFpZXYNCg==
------WebKitFormBoundarySKPlgJRINOMnpxVP--

更新

@Ubercode建议我将base 64转换为string,我做到了,但看起来很恶心:

1
2
3
4
5
6
7
8
9
10
var buffer = await file.ReadAsStreamAsync();

TextReader textReader = new StreamReader(buffer);
var text = textReader.ReadToEnd();
var indexOfWord ="base64,";
var base64EncodedBytes = System.Convert.FromBase64String(text.Substring(text.IndexOf(indexOfWord) + indexOfWord.Length));
var encoded = System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
TextReader textReader2 = new StringReader(encoded);
var csv = new CsvReader(textReader2);
var records = csv.GetRecords<BulkUploadUser>().ToList();


您需要将base64编码的内容解码到您的文件中:

如何对base 64字符串进行编码和解码

您可以稍微整理一下代码,这样:

1
2
3
4
5
6
7
8
9
10
11
12
string text;
using(TextReader textReader = new StreamReader(buffer))
     text = textReader.ReadToEnd();

CsvReader csv;

using(var ms
   = new MemoryStream(Convert.FromBase64String(text.Substring(text.IndexOf(',') + 1)))
using (var textReader2 = new StreamReader(ms))
    csv = new CsvReader(textReader2);

var records = csv.GetRecords<BulkUploadUser>().ToList();


我也有同样的问题,谢谢你在这篇文章中的建议。

首先,上传一个文件有两种可能:HTTPPOST内容或表单数据(也是POST,但不完全相同)。

我使用的是更简单的方法,HTTP Post内容。base64编码等没有问题,解决方案仍然很简单,但我认为对于大文件来说,这可能是非常无用的。

我在Angular项目中使用了以下代码:

角度编码

导入对话框(HTML):

1
2
3
4
<input hidden #imageInput type="file" accept=".csv" (change)="processFile(imageInput)">
<button mat-button class="image-upload-button full-width" (click)="imageInput.click()">
   <mat-icon>add</mat-icon>
</button>

对话代码(.ts)

1
2
const file: File = imageInput.files[0];
this.dialogRef.close(file);

对话框关闭后执行的TS代码

1
2
const url = 'myapi/Import';
return this.http.post<ImportResult>(url, file).toPromise();

C码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
try
{
    var result = new ImportResult();
    s = System.Web.HttpContext.Current.Request.GetBufferedInputStream();
    using (var sr = new System.IO.StreamReader(s))
    {
        s = null;
        var reader = new CsvReader(sr, new CsvConfiguration
        {
            Delimiter =";"
        });
        var records = reader.GetRecords<RowEntry>();
        ...
    }
    return result;
}
finally
{
    s?.Dispose();
}

希望这会有所帮助,这是一个简单的解决方案,可以很好地工作。


上传的数据确实是csv,而不是excel:

1
2
3
4
Email,FirstName,LastName
prosto.duda@gmail.com2,Denis,Dudaiev
prosto.duda@gmail.com,Denis,Dudaiev
prosto.duda@gmail.com2,Denis,Dudaiev

最好首先防止数据转换为base64(它更大,需要解码)。

出于某种原因,数据以"excel"的形式发送,并以base64的形式发送:

1
data:application/vnd.ms-excel;base64,

因此,您可能需要检查以下内容:

1
2
3
4
headers: {
   "Content-Type": undefined
},
transformRequest: angular.identity,

我不知道AngularJS,但你可能想把Content-Type改成text/csv,检查transformRequest

或者在这里转换成base64:

1
2
var fd = new FormData();
fd.append("file", bulkUsersFile);

所以最好检查数据在哪里转换,并将其修复为发送纯文本。这将阻止编码/解码步骤,数据也将变小。


1
2
3
4
5
6
7
8
        if (!Request.Content.IsMimeMultipartContent())
        {
            return StatusCode(HttpStatusCode.UnsupportedMediaType);
        }

        HttpPostedFile uploadedFile = HttpContext.Current.Request.Files[0];

         var csv = new CsvReader(uploadedFile.InputStream);