【问题标题】:C# String missing characters in WindowsForm AppWindows 窗体应用程序中的 C# 字符串缺少字符
【发布时间】:2017-10-13 15:26:20
【问题描述】:

我正在构建一个网络扫描实用程序应用程序,但在列表视图中显示字符串时遇到了一些问题。

我通过套接字请求和字节编码查找本地远程计算机的 Netbios 名称,当我在列表视图中显示结果时,域名根本不显示,但是当我导出该列表视图行子项的文本时在 .csv 文件中包含机器的 NetBios 名称它会正确显示整个字符串,例如“COMPUTER1-WORKGROUP”,例如在列表视图中它只会显示“COMPUTER1”。

这里你可以在windows应用程序的listview中看到显示:

正如您在第一行的“Nom Netbios”列中看到的,它只显示“NVRSERVEUR”

然后,当我将 ListViewItem.SubItem.Text 写入 .csv 文件时,如下图所示,它显示“NVRSERVEUR-IRIS”,其中 IRIS 代表网络域名。

这是我用于检索 netbios 计算机名称和网络域名的任务代码:

static Task<NetworkInfosWrapper> getNetBiosNameAsyncReply(PingReply reply)
    {
        var tcs = new TaskCompletionSource<NetworkInfosWrapper>();
        byte[] receiveBuffer = new byte[1024];
        Socket requestSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        requestSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 100);
        EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(reply.Address.ToString()), 137);
        IPEndPoint originEndPoint = new IPEndPoint(IPAddress.Any, 0);
        requestSocket.Bind(originEndPoint);
        SocketAsyncEventArgs e = new SocketAsyncEventArgs();
        e.SetBuffer(NameRequest, e.Offset, NameRequest.Count());
        e.RemoteEndPoint = remoteEndPoint;
        e.Completed += (obj, sender) =>
        {
            try
            {
                int receivedByteCount = requestSocket.ReceiveFrom(receiveBuffer, ref remoteEndPoint);
                if (receivedByteCount >= 90)
                {
                    Encoding enc = new UTF8Encoding();
                    //Encoding enc = new ASCIIEncoding();

                    string deviceName = enc.GetString(receiveBuffer, 57, 16).Trim();
                    string networkName = enc.GetString(receiveBuffer, 75, 16).Trim();

                    tcs.SetResult(new NetworkInfosWrapper(reply,(deviceName.Trim()+" - "+networkName.Trim()).Replace(" ", "")));

                }
                else
                {
                    tcs.SetResult(new NetworkInfosWrapper(reply, "N/A"));
                }
            }
            catch
            {
                tcs.SetResult(new NetworkInfosWrapper(reply, "N/A"));
            }

        };
        requestSocket.SendToAsync(e);
        return tcs.Task;
    }

这是我在主扫描功能的列表视图中显示它的方式:

foreach (var netbiosTask in netbiosTasks)
        {
            if (netbiosTask.Result.reply.Status == IPStatus.Success)
            {
                ListViewItem lvi;
                addr = IPAddress.Parse(netbiosTask.Result.reply.Address.ToString());
                string mac = ScanUtils.getMacByIp(netbiosTask.Result.reply.Address.ToString());

                lvi = new ListViewItem(ScanUtils.GetReverseDNS(netbiosTask.Result.reply.Address.ToString(),1000));
                lvi.SubItems.Add(netbiosTask.Result.reply.Address.ToString());
                lvi.SubItems.Add("UP");
                lvi.SubItems.Add(netbiosTask.Result.reply.RoundtripTime.ToString() + " ms");
                lvi.SubItems.Add(netbiosTask.Result.netBiosName);
                lvi.SubItems.Add(mac);
                lvi.SubItems.Add(ScanUtils.getMacvendor(mac));
                listView.Items.Add(lvi);
                if(progressBar1.Value < progressBar1.Maximum) {
                    progressBar1.Value = progressBar1.Value + 1;
                }
                if (!mStopThread)
                {
                    break;
                }
            }
        }

这是我将列表视图的内容导出为 .csv 文件的方法:

private void enregistrerBtn_Click(object sender, EventArgs e)
    {
        StringBuilder csvContent = new StringBuilder();
        csvContent.AppendLine("sep=;");
        csvContent.AppendLine("Hostname;Adresse IP;Netbios;Adresse Mac;Mac Vendor");

        foreach (ListViewItem item in listView.Items)
        {
            csvContent.AppendLine(string.Format("{0};{1};{2};{3};{4}", item.SubItems[0].Text, item.SubItems[1].Text, item.SubItems[4].Text, item.SubItems[5].Text, item.SubItems[6].Text));
        }

        string csvPath = Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory).ToString() + @"\Resources\networkScan"+ DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss") +".csv";

        File.AppendAllText(csvPath, csvContent.ToString(),Encoding.UTF8);
    }

我尝试对 csv 写入和套接字响应的字节编码同时使用 ASCII 和 UTF-8 编码。 其他人遇到过这种问题吗?

【问题讨论】:

    标签: c# string csv listview encoding


    【解决方案1】:

    Trim 默认情况下不会从字符串中删除空字节,只会删除空格字符。专门应用Trim 来删除这样的空字节:

    string deviceName = enc.GetString(receiveBuffer, 57, 16).Trim('\0');
    string networkName = enc.GetString(receiveBuffer, 75, 16).Trim('\0');
    

    您是否看到空字节之后的字符串部分取决于您如何显示它们。列表视图在看到空字节时停止打印文本,用于查看 CSV 文件(Excel?)的编辑器似乎能够在空字节后继续。

    【讨论】:

    • 感谢您的快速回答,我刚刚尝试过,确实有效!如果我自己能找到这个,我不是很有经验,我也不知道!我使用 Excel 是的,对此我感到非常困惑,现在我明白了,感谢您的解释。干杯
    • 现在我可以使用更多帮助,因为对于某些设备的网络域名,我有未知字符显示如下:imgur.com/qMKsAlr,如果它检测到一些未知字符,你知道我该如何摆脱这些,或者也许翻译得更好?谢谢
    • 试试this questionTrimFromZero函数
    • 如果这不起作用,可能是 NetBIOS 协议没有使用 null 来确定字符串的结尾。也许协议将字符串的实际长度与回复一起发送到某处?
    • 好吧,我试图让它工作,但还没有结果,它现在没有任何改变!我会尝试更深入地挖掘你的推理,你可能是对的,我会尽快给你一些反馈:) 非常感谢你是真正的 mvp!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 2015-03-15
    • 1970-01-01
    相关资源
    最近更新 更多