通过 TcpClient 接收的 XPS 文件已损坏
本文关键字:XPS 文件 已损坏 TcpClient 通过 | 更新日期: 2023-09-27 18:33:57
我正在尝试用 C# 创建一个"虚拟打印机"应用程序,该应用程序通过网络接收打印作业,解析原始打印数据以获取某些信息,然后将文档保存到数据库中。 以下类的修改版本适用于 postscript 打印作业(它将传入数据保存到有效的 .prn 文件中,就像打印机设置为打印到"FILE:"端口一样。 当我尝试捕获.但是,Microsoft XPS 文档编写器中的 XPS 文档无法打开这些文档。 如果扩展名被重命名,有效的XPS文件也应该是有效的ZIP文件,这也不起作用。 当我将同一文档打印到 FILE: 端口,然后打印到我的应用程序,并在 Notepad++ 中比较结果时,数据长度有 5 个字符的差异,但它看起来相同(它不是纯文本,所以很难看,但前几个字符和最后几个字符似乎是相同的(。 以"正常"方式保存的文件工作正常,但由我的代码生成的文件则不然。
更一般地说,我尝试通过TCP端口接收任意数据并将其写入文件。 我的解决方案是"接近"但不起作用。 我不知道XPS使用什么样的编码,但我使用ASCII作为后记,我已经尝试了ASCII和UTF8用于这个XPS版本。
任何帮助将不胜感激! 这是我代码的相关部分:
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();
}
你的代码中至少有两个问题,其中一个几乎可以肯定是你写的文件不正确的原因:
- 您不断重新打开要写入的文件,而不仅仅是打开一次。
- 您正在将收到的字节解释为文本,然后重新编码它们。
第一个问题与其说是正确性问题,不如说是效率/文件锁定问题。但第二个是大问题。
如您所知,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)
。