解决 CSVHelper引发错误为"找不到标题记录"

安奇

会员
已加入
2020年12月16日
留言内容
17
编程经验
3-5
嗨,以下是我尝试读取csv并尝试将文件复制到表格存储中的代码,但是我收到以下错误消息:"找不到标题记录".
以下是我试图阅读的示例csv

C#:
Sample CSv to be read:

PartitionKey;Time;RowKey;State;RPM;Distance;RespirationConfidence;HeartBPM
te123;2020-11-06T13:33:37.593Z;10;1;8;20946;26;815
te123;2020-11-06T13:33:37.593Z;4;2;79944;8;36635;6
te123;2020-11-06T13:33:37.593Z;3;3;80042;9;8774;5
te123;2020-11-06T13:33:37.593Z;1;4;0;06642;6925;37
te123;2020-11-06T13:33:37.593Z;6;5;04740;74753;94628;21
te123;2020-11-06T13:33:37.593Z;7;6;6;2;14;629
te123;2020-11-06T13:33:37.593Z;9;7;126;86296;9157;05
te123;2020-11-06T13:33:37.593Z;5;8;5;3;7775;08
te123;2020-11-06T13:33:37.593Z;2;9;44363;65;70;229
te123;2020-11-06T13:33:37.593Z;8;10;02;24666;2;2



C#:
    public Type DataType
        {
            get
            {
                switch( Type.ToUpper() )
                {
                    case "STRING":
                        return typeof(string);

                    case "INT":
                        return typeof( int );

                    case "BOOL":
                    case "BOOLEAN":
                        return typeof( bool );

                    case "FLOAT":
                    case "SINGLE":
                    case "DOUBLE":
                        return typeof( double );

                    case "DATETIME":
                        return typeof( DateTime );

                    default:
                        throw new NotSupportedException( $"CSVColumn data type '{Type}' not supported" );
                }
            }
        }
// This is the method where the stream is passed and the error is received at line "csv.ReadHeader()"
private IEnumerable<Dictionary<string, EntityProperty>> ReadCSV(Stream source, IEnumerable<TableField> cols)
        {
            var size = source.Length;
            source.Position = 0;
            using (TextReader reader = new StreamReader(source, Encoding.UTF8))
            {
                var cache = new TypeConverterCache();
                reader.ReadLine();
                cache.AddConverter<float>(new CSVSingleConverter());
                cache.AddConverter<double>(new CSVDoubleConverter());
                var csv = new CsvReader(reader,
                    new CsvHelper.Configuration.CsvConfiguration(global::System.Globalization.CultureInfo.InvariantCulture)
                    {
                        Delimiter = ";",
                        HasHeaderRecord = true,
                        CultureInfo = global::System.Globalization.CultureInfo.InvariantCulture,
                        TypeConverterCache = cache
                    });
                csv.Read();
                csv.ReadHeader();

                var map = (
                        from col in cols
                        from src in col.Sources()
                        let index = csv.GetFieldIndex(src, isTryGet: true)
                        where index != -1
                        select new { col.Name, Index = index, Type = col.DataType }).ToList();

                while (csv.Read())
                {
                    yield return map.ToDictionary(
                        col => col.Name,
                        col => EntityProperty.CreateEntityPropertyFromObject(csv.GetField(col.Type, col.Index)));
                }

            }

        }
// This is the method from where the stream is being returned to ReadCsv() method above
public async Task<Stream> ReadStream(string containerName, string digestFileName, string fileName, string connectionString)
        {
            string data = string.Empty;
            string fileExtension = Path.GetExtension(fileName);
            var contents = await 下载Blob(containerName, digestFileName, connectionString);             
              
          
            return contents;
        }

// method where blob is read as stream
public async Task<Stream> 下载Blob(string containerName, string fileName, string connectionString)
        {
          
            Microsoft.Azure.Storage.CloudStorageAccount storageAccount = Microsoft.Azure.Storage.CloudStorageAccount.Parse(connectionString);
            CloudBlobClient serviceClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = serviceClient.GetContainerReference(containerName);
            CloudBlockBlob blob = container.GetBlockBlobReference(fileName);
            if (!blob.Exists())
            {
                throw new Exception($"Unable to upload data in table store for document");
            }
          
            return await blob.OpenReadAsync();
          
        }
 
Last edited:

安奇

会员
已加入
2020年12月16日
留言内容
17
编程经验
3-5
好吧,这似乎不是这次,如果您看到我上一次正在阅读并传递MemoryStream的话,那对我的readCSV()方法就可以了。现在,如果有很大的csv文件,那么在内存中读取并不是一个理想的解决方案,这就是为什么我们要使用OpenRead()方法读取Stream的原因,该方法返回流的对象。在流中,我可以看到内容的长度。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,499
地点
弗吉尼亚州切萨皮克
编程经验
10+
因此,您具有流的长度,是否查看了头几个字节以确保标题行确实是第一行,而不是空行?
 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,028
地点
挪威
编程经验
10+
输入流的下一行;如果到达输入流的末尾,则为null。
因此,这是与您其他线程相同的问题。您的流可能已将Position设置为结束,请在尝试读取流之前尝试设置stream .Position = 0。如果执行此操作,ReadLine返回什么?
 

安奇

会员
已加入
2020年12月16日
留言内容
17
编程经验
3-5

因此,这是与您其他线程相同的问题。您的流可能已将Position设置为结束,请在尝试读取流之前尝试设置stream .Position = 0。如果执行此操作,ReadLine返回什么?
streams.Position = 0给我未设置空对象引用。我将其放在ReadCsv()方法的开头。其他论坛上的其他讨论表明,Csvhelper不支持该流。仅支持内存和FileStream。我不能忽略这一点,但想知道是否有人使用CsvHelper读取了Stream
 
Last edited:

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,499
地点
弗吉尼亚州切萨皮克
编程经验
10+
这与上面的线程相切。在该论坛的一个旧话题中,一个发帖人在问为什么某个特定的流操作失败,然后在重现该问题然后挖掘源代码之后,我发现HTTP网络流中存在一个问题,其中有一个极端的案例。需要在数据流中的特定位置进行换行,并且调用方尝试读取多个字节(我记得为零字节)会混淆网络流实现的内部数据结构。 MS承认了该错误,但拒绝修复此错误,因为它是一种罕见的极端情况。

鉴于Microsoft工程师跨部门或跨业务时倾向于复制代码-对反托拉斯诉讼的直截了当的反应以及公司破裂的​​威胁-可能同一错误可能已将其纳入Azure数据Blob流实现中。

在我看来,这纯粹是猜测,可能性很小。我认为我们的OP处理流的可能性更高,特别是考虑到上一个帖子,他在尝试重置流位置时对流的引用为空。

同样,大多数网络流实现不支持查找。因此,如果CsvHelper需要寻求支持(也有人认为CsvHelper仅支持FileStream和MemoryStream),则直接与网络流进行通信将导致失败。您可能需要走简单的路线,首先将所有内容读入MemoryStream(这是您要避免的事情),或者在网络流周围实现自己的流包装器以支持缓冲和查找。
 

安奇

会员
已加入
2020年12月16日
留言内容
17
编程经验
3-5
如果stream为null,并且以前没有发生过,则StreamReader会引发ArgumentNullException,那么为什么现在要这样做呢?
streams.Position = 0被设置为ReadCsv()方法中的第一件事,并且我得到未设置为实例的对象引用。虽然我在快速观看流中看到了有效的位置和长度
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,499
地点
弗吉尼亚州切萨皮克
编程经验
10+
对我来说听起来很奇怪。您确定要测试与编译相同的代码吗?

顺便说一句,请发布您的更新代码。
 

安奇

会员
已加入
2020年12月16日
留言内容
17
编程经验
3-5
对我来说听起来很奇怪。您确定要测试与编译相同的代码吗?

顺便说一句,请发布您的更新代码。
使用最新的readCsv()方法更新了代码。如果某个天蓝色的人可以从头开始进行测试,请像我使用DownloadBlob方法一样读取blob,并将要由csvHelper读取的流传递给我。
 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,028
地点
挪威
编程经验
10+
使用最新的readCsv()方法更新了代码
更改此线程中已经讨论了一段时间的先前代码不是一个好主意,它可能会使以下答复看起来很奇怪和错误。相反,您应该使用新代码编写新帖子,以便我们可以跟踪进度。

无论如何,更新后的帖子1中的第38行不应该出现,它会破坏您的代码。您应该按照第7篇 测试 第一行现在返回的内容。测试之后,您必须停止程序,因为从流中读取一行将破坏后面的代码。您应该在IM中看到的值是标题字符串。如果那是结果,那么您就走对了,可以继续进行。修改代码,进行测试,然后确认。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,499
地点
弗吉尼亚州切萨皮克
编程经验
10+
使用最新的readCsv()方法更新了代码。
没有!不要在此论坛(以及大多数其他带线程的论坛)上这样做。在StackOverflow上更新问题也许是公认的做法(因为那里的响应没有线程化),但是这里没有。
 

安奇

会员
已加入
2020年12月16日
留言内容
17
编程经验
3-5
终于,问题解决了。这是一个StreamReader,它将流的位置设置为末尾,这就是为什么它返回null的原因,由于某种原因,我仍然无法将Position设置为0,但是现在在ReadCsv()中调用该函数并删除StreamReader之前
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,499
地点
弗吉尼亚州切萨皮克
编程经验
10+
很高兴您解决了它。我希望您花时间来更新所有其他交叉点,以便其他人不会在浪费时间继续尝试回答您的问题。

希望有一天,您还将解释为什么在使用MemoryStream或FileStream而不是Azure blob流时让StreamReader起作用。
 
最佳 底部