通过TcpClient收到的XPS文件已损坏

时间:2014-12-10 22:26:02

标签: c# printing tcpclient xps

我正在尝试在C#中创建一个“虚拟打印机”应用程序,通过网络接收打印作业,解析原始打印数据以获取某些信息,然后将文档保存到数据库中。以下类的修改版本用于postscript打印作业(它将传入的数据保存到有效的.prn文件,就像打印机设置为打印到“FILE:”端口一样。)当我尝试捕获时。但是,来自Microsoft XPS Document Writer的XPS文档无法打开文档。如果重命名扩展名,则有效的XPS文件也应该是有效的ZIP文件,这也不起作用。当我将相同的文档打印到FILE:端口然后打印到我的应用程序,并且我在Notepad ++中比较结果时,数据长度存在5个字符的差异,但它看起来完全相同(它不是纯文本所以它是很难看,但前几个字符和最后几个字符看起来是一样的)。保存“正常”方式的文件工作正常,但我的代码生成的文件没有。

更一般地说,我试图通过TCP端口接收任意数据并将其写入文件。我的解决方案是“关闭”但不起作用。我不知道XPS使用什么样的编码,但我使用ASCII作为postscript,我已经为这个XPS版本尝试了ASCII和UTF8。

非常感谢任何帮助!这是我的代码的相关部分:

class XPSListener
    {
        private TcpListener tcpListener;
        private Thread listenThread;
        private string instanceName = "";
        private string fileShare = (Settings.Default.SharedPath.Substring(Settings.Default.SharedPath.Length - 1) == @"\") ? Settings.Default.SharedPath : Settings.Default.SharedPath + @"\"; // use SharedPath setting value - append backslash if it isn't already there.

        public XPSListener(string initInstanceName, Int32 initPort)
        {
            this.instanceName = initInstanceName;
            this.tcpListener = new TcpListener(IPAddress.Any, initPort);
            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.Start();
        }

        private void ListenForClients()
        {
            try
            {
                this.tcpListener.Start();
            }
            catch (Exception e)
            {
                MessageBox.Show("Socket Error 1 - " + e.StackTrace);
            }

            while (true)
            {
                //blocks until a client has connected to the server
                TcpClient client = this.tcpListener.AcceptTcpClient();

                //create a thread to handle communication with connected client
                Thread clientThread = new Thread(new ParameterizedThreadStart(AcceptXPSData));
                clientThread.Start(client);
            }
        }

        private void AcceptXPSData(object client)
        {
            TcpClient tcpClient = (TcpClient)client;
            NetworkStream clientStream = tcpClient.GetStream();
            string tempFilePath = fileShare + "XPStemp_" + instanceName + ".oxps";

            byte[] message = new byte[65536];
            int bytesRead;
            string input;

            while (true)
            {
                bytesRead = 0;

                try
                {
                    //blocks until a client sends a message
                    bytesRead = clientStream.Read(message, 0, 65536);
                    Debug.WriteLine("Bytes read: " + bytesRead.ToString());  
                }
                catch
                {
                    //a socket error has occured
                    break;
                }

                if (bytesRead == 0)
                {
                    //the client has disconnected from the server
                    break;
                }

                //message has successfully been received
                if (instanceName != "DontPrint")
                {
                    Debug.WriteLine(instanceName + " Receiving Data");
                    //ASCIIEncoding encoder = new ASCIIEncoding();
                    UTF8Encoding encoder = new UTF8Encoding();

                    using (FileStream fs = new FileStream(tempFilePath, FileMode.Append, FileAccess.Write))
                    {
                        using (StreamWriter sw = new StreamWriter(fs))
                        {
                            input = encoder.GetString(message, 0, bytesRead);
                            sw.Write(input);
                            // first capture this input and write it to an xps file.  This file can be converted to PDF at a later time by Ghostscript
                            // but we will still have access to the temp file for parsing purposes.
                        }
                    }
                }
                
               
            }

            tcpClient.Close();

            // processXPS();
        }

1 个答案:

答案 0 :(得分:1)

您的代码中至少有两个问题,其中一个问题几乎肯定是您编写的文件不正确的原因:

  1. 您继续重新打开您要写入的文件,而不是仅仅打开一次。
  2. 您正在将您收到的字节解释为文本,然后重新编码。
  3. 第一个问题更多的是效率/文件锁定问题,而不是正确性问题。但第二个是一个大问题。

    您似乎意识到,XPS文件基本上是.zip文件。这意味着虽然底层数据是XML(即UTF8),但文件本身是压缩的二进制文件。你无法以任何有意义的方式将其解释为文本。

    您应该直接将您读取的字节写入文件。更好的代码版本如下所示:

    private void AcceptXPSData(object client)
    {
        string tempFilePath = fileShare + "XPStemp_" + instanceName + ".oxps";
    
        using (TcpClient tcpClient = (TcpClient)client)
        using (NetworkStream clientStream = tcpClient.GetStream())
        using (FileStream fs = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
        {
            clientStream.CopyTo(fs);
        }
    
        // processXPS();
    }
    

    如果您确实想要监视I / O,可以明确地处理它,但仍然比代码更简单:

    private void AcceptXPSData(object client)
    {
        string tempFilePath = fileShare + "XPStemp_" + instanceName + ".oxps";
    
        using (TcpClient tcpClient = (TcpClient)client)
        using (NetworkStream clientStream = tcpClient.GetStream())
        using (FileStream fs = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
        {
            byte[] message = new byte[65536];
            int bytesRead;
    
            while ((bytesRead = clientStream.Read(message, 0, message.Length)) > 0)
            {
                fs.Write(message, 0, bytesRead);
    
                // Add logging or whatever here
            }
        }
    
        // processXPS();
    }
    

    请注意,如果您想要处理异常,则只需要处理您可能会发生的特定情况,并且您有合理的处理方式。在这样的代码中应该避免使用catch子句或宽catch (Exception)