-2

我试图将 csv 文件的内容读入不同的变量,以便发送到 Web 服务。它工作正常,但今天突然出现异常。

指数数组的边界之外:

我做错了什么?

String sourceDir = @"\\198.0.0.4\e$\Globus\LIVE\bnk.run\URA.BP\WEBOUT\";
// Process the list of files found in the directory. 
string[] fileEntries = Directory.GetFiles(sourceDir);
foreach (string fileName2 in fileEntries)
{
    // read values
    StreamReader st = new StreamReader(fileName2);
    while (st.Peek() >= 0)
    {
        String report1 = st.ReadLine();
        String[] columns = report1.Split(','); //split columns 
        String prnout = columns[0];
        String tinout = columns[1];
        String amtout = columns[2];
        String valdate = columns[3];
        String paydate = columns[4];
        String status = columns[5];
        String branch = columns[6];
        String reference = columns[7];
    }
}
4

4 回答 4

1

只是为了理智,我把这里写的所有不同的笔记结合起来。这段代码更简洁一些,并且有一些验证。

尝试这个:

string dir = @"\\198.0.0.4\e$\Globus\LIVE\bnk.run\URA.BP\WEBOUT\";
foreach (string fileName2 in Directory.GetFiles(dir)) {
    StreamReader st = new StreamReader(fileName2);
    while (!sr.EndOfStream)  {
        string line = sr.ReadLine();
        if (!String.IsNullOrEmpty(line)) {
            string[] columns = line.Split(',');
            if (columns.Length == 8) {
                string prnout = columns[0];
                string tinout = columns[1];
                string amtout = columns[2];
                string valdate = columns[3];
                string paydate = columns[4];
                string status = columns[5];
                string branch = columns[6];
                string reference = columns[7];
            }
        }
    }
}

编辑:正如其他一些用户所评论的,CSV 格式也接受文本限定符,这通常意味着双引号 (")。例如,文本限定行可能如下所示:

user,"Hello!",123.23,"$123,123.12",and so on,

当您拥有像这样完全格式化的文件时,编写 CSV 解析代码会稍微复杂一些。多年来,我一直在解析格式不正确的 CSV 文件,我编写了一个几乎通过所有单元测试的标准代码脚本,但解释起来很痛苦。

/// <summary>
/// Read in a line of text, and use the Add() function to add these items to the current CSV structure
/// </summary>
/// <param name="s"></param>
public static bool TryParseLine(string s, char delimiter, char text_qualifier, out string[] array)
{
    bool success = true;
    List<string> list = new List<string>();
    StringBuilder work = new StringBuilder();
    for (int i = 0; i < s.Length; i++) {
        char c = s[i];

        // If we are starting a new field, is this field text qualified?
        if ((c == text_qualifier) && (work.Length == 0)) {
            int p2;
            while (true) {
                p2 = s.IndexOf(text_qualifier, i + 1);

                // for some reason, this text qualifier is broken
                if (p2 < 0) {
                    work.Append(s.Substring(i + 1));
                    i = s.Length;
                    success = false;
                    break;
                }

                // Append this qualified string
                work.Append(s.Substring(i + 1, p2 - i - 1));
                i = p2;

                // If this is a double quote, keep going!
                if (((p2 + 1) < s.Length) && (s[p2 + 1] == text_qualifier)) {
                    work.Append(text_qualifier);
                    i++;

                    // otherwise, this is a single qualifier, we're done
                } else {
                    break;
                }
            }

            // Does this start a new field?
        } else if (c == delimiter) {
            list.Add(work.ToString());
            work.Length = 0;

            // Test for special case: when the user has written a casual comma, space, and text qualifier, skip the space
            // Checks if the second parameter of the if statement will pass through successfully
            // e.g. "bob", "mary", "bill"
            if (i + 2 <= s.Length - 1) {
                if (s[i + 1].Equals(' ') && s[i + 2].Equals(text_qualifier)) {
                    i++;
                }
            }
        } else {
            work.Append(c);
        }
    }
    list.Add(work.ToString());

    // If we have nothing in the list, and it's possible that this might be a tab delimited list, try that before giving up
    if (list.Count == 1 && delimiter != DEFAULT_TAB_DELIMITER) {
        string[] tab_delimited_array = ParseLine(s, DEFAULT_TAB_DELIMITER, DEFAULT_QUALIFIER);
        if (tab_delimited_array.Length > list.Count) {
            array = tab_delimited_array;
            return success;
        }
    }

    // Return the array we parsed
    array = list.ToArray();
    return success;
}

您应该注意,即使该算法如此复杂,它仍然无法解析在文本限定值中嵌入换行符的 CSV 文件,例如:

123,"Hi, I am a CSV File!
I am saying hello to you!
But I also have embedded newlines in my text.",2012-07-23

为了解决这些问题,我有一个多行解析器,它使用 Try() 功能添加额外的文本行来验证主函数是否正常工作:

/// <summary>
/// Parse a line whose values may include newline symbols or CR/LF
/// </summary>
/// <param name="sr"></param>
/// <returns></returns>
public static string[] ParseMultiLine(StreamReader sr, char delimiter, char text_qualifier)
{
    StringBuilder sb = new StringBuilder();
    string[] array = null;
    while (!sr.EndOfStream) {

        // Read in a line
        sb.Append(sr.ReadLine());

        // Does it parse?
        string s = sb.ToString();
        if (TryParseLine(s, delimiter, text_qualifier, out array)) {
            return array;
        }
    }

    // Fails to parse - return the best array we were able to get
    return array;
}
于 2012-07-23T16:36:03.040 回答
1

甚至没有看到 .csv 文件就很难猜到,但我的第一个是你没有 8 列。

如果您可以显示原始 .csv 文件并告诉我们异常出现的位置会更容易。

编辑:如果您认为数据没问题,我建议您调试并查看拆分调用在 Visual Studio 中返回的内容。这可能会有所帮助

编辑2:由于您是在循环中进行该处理,因此请确保每行至少有 8 列。

于 2012-07-23T16:28:13.357 回答
1

我的钱花在了坏数据文件上。如果这是等式中唯一发生变化的事情(也就是您没有进行任何代码更改),那么这几乎是您唯一的选择。

如果您的数据文件不太长,请在此处发布,我们可以肯定地告诉您。

您可以添加如下内容来检查无效的列长度:

while (st.Peek() >= 0)
{
    String report1 = st.ReadLine();
    String[] columns = report1.Split(','); //split columns 

    if(columns.Length < 8)
    {
         //Log something useful, throw an exception, whatever.  
         //You have the option to quitely note that there was a problem and 
         //continue on processing the rest of the file if you want.
         continue;
    }

    //working with columns below
}
于 2012-07-23T16:29:39.153 回答
0

由于您不知道 csv 文件中有多少列,您可能需要测试长度:

if (columns.Length == 8) {
     String prnout = columns[0];
     String tinout = columns[1];
     ...
}

我敢打赌你只是得到了一个空行(最后是额外的 EOL),就这么简单

于 2012-07-23T16:30:14.743 回答