0

我正在使用套接字在java中开发一个http web服务器,它获取post header InputStream,然后我用一些由标题'boundary'和'\r\n'分割的字符串处理了标题,并得到了HashMap(s)中的所有标题和Cookie并以字符串形式获取文件的内容并将该字符串保存到服务器上的文件中。当我将文本文件或 java 源文件上传到服务器时,它工作正常,但在 doc、pdf 和图像的情况下,它显示损坏的文件和损坏的图像。

    PrintWriter out;
        try {
            out = new PrintWriter(new OutputStreamWriter(
                    new FileOutputStream(UploadPath + "\\" + FileName)));
            out.print(FileData);
            out.close();
        } catch (Exception e) {

        }

上面的代码将在 'UploadPath' 中使用 'FileName' 保存 'FileData' 的内容。

如果是 jpg 或 doc 文件 String FileData 具有由上述代码保存的上传文件的二进制内容,我还检查了这两个文件的字节大小,并且它们的字节大小相同,并且我还匹配了实际的内容文件和内容 FileData String 通过调试应用程序。

我还检查了实际上传的图像文件和 FileData 字符串,两者都逐字节匹配,但上传的图像完全损坏。

在互联网上搜索了这一天之后,我无法找到解决方案。请帮忙。

我不想使用大多数页面上建议的 apache commons。

如果您想查看更多代码,那么我将发布它们。

4

4 回答 4

1

当你处理二进制数据时,你应该使用byteandOutputStream而不是Stringand Writer:如果你把一些字节放在一个字符串中,它们会被解码

因此,如果您在请求中找到了二进制数据的边界(由字节数组表示),请将内容按字节直接复制到输出流。

这仅在您的请求已经完全在内存中时才有效。关于文件上传,这并不总是可行的,因为如果您有大文件,您可能会耗尽内存。

所以实现文件上传的最佳方式是只从流中读取下一个字节:这就是拆分解析的区别。实际上,您需要一个真正的解析器来处理多部分表单数据。现在事情变得复杂了,这就是每个人都使用 commons-fileupload 的原因:如果您的“前瞻”只是一些字节,那么检测边界并不容易。

出于法律原因,我不得不实施洁净室实施。如果这不是您的情况,请查看 commons-fileupload 的来源。并查看RFC

于 2013-06-09T13:36:23.940 回答
0

由于您使用 Java 7,这很容易:使用Files.copy()

此外,请勿将文件内容存储为Strings,这些内容仅对文本文件有效。使用classic InputStream/ OutputStreams 来读/写。

于 2013-06-09T12:28:59.837 回答
0

您可以使用如下所示的字节数组读取它

InputStream is = ...
ByteArrayOutputStream buffer = new ByteArrayOutputStream();

int nRead;
byte[] data = new byte[16384];

while ((nRead = is.read(data, 0, data.length)) != -1) {
  buffer.write(data, 0, nRead);
}

buffer.flush();

return buffer.toByteArray();
于 2013-06-09T12:31:18.723 回答
0

我这样解决了我的问题,

    while (inputRequest.available()>0) {
            try {
                int t = inputRequest.read();
                ch = (char) t;
                //here i checked each byte data
            } catch (IOException e) {
            }
    }

问题是输入流具有 http 标头字段以及位于流中任何位置的文件内容,因此我首先将字节存储在临时字符串中,直到在流中获得 '\r' 和 '\n' 。通过这种方式,我得到了 multipart/form-data HTTP 标头的边界,然后我比较了临时字符串,直到找到边界和其他已知标头内容,然后我将输入流发送到文件输出流。但在某些情况下,标题可能在文件内容之后包含其他内容,因此它肯定会有一个结束边界,所以我不断跟踪我读取的每个字节,然后我将每个字节单独发送到文件输出流。这是示例 http 标头-

   Host: localhost
   User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
   Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
   Accept-Language: en-US,en;q=0.5
   Accept-Encoding: gzip, deflate
   DNT: 1
   Referer: http://localhost/index.html
   Connection: keep-alive
   Content-Type: multipart/form-data; boundary=---------------------------274761981030199
   Content-Length: 1405

   -----------------------------274761981030199
   Content-Disposition: form-data; name="name1"

   pppppp
   -----------------------------274761981030199
   Content-Disposition: form-data; name="name2"

   rrrrrrrrr
   -----------------------------274761981030199
   Content-Disposition: form-data; name="name3"

   eeeeeeee
   -----------------------------274761981030199
   Content-Disposition: form-data; name="name4"

   2
   -----------------------------274761981030199
   Content-Disposition: form-data; name="name5"; filename="CgiPost.java"
   Content-Type: text/x-java-source

   import java.io.*;

   // This appears in Core Web Programming from
   // Prentice Hall Publishers, and may be freely used
   // or adapted. 1997 Marty Hall, hall@apl.jhu.edu.


   public class CgiPost extends CgiGet 
   {

   public static void main(String[] args) 
   {

   try 
   {

   DataInputStream in
    = new DataInputStream(System.in);

   String[] data = { in.readLine() };

   CgiPost app = new CgiPost("CgiPost", data, "POST");

   app.printFile();
       } catch(IOException ioe) {
         System.out.println
           ("IOException reading POST data: " + ioe);

   }
     }

     public CgiPost(String name, String[] args,
     String type) {
       super(name, args, type);
     }
   }

   -----------------------------274761981030199
   Content-Disposition: form-data; name="name6"

   pppppppppp
   -----------------------------274761981030199--

注意:在某些情况下,您的应用程序代码可能会到达 inputRequest.available() 但浏览器尚未发送请求,在这种情况下 inputRequest.available() 将始终返回 0 并且您的 while 循环将立即退出。为了避免这种情况,首先使用 inputRequest.read() 读取一个字节,然后执行代码,因为在 http 标头的情况下,您可以猜测其他字节的第一个字节。

如果您使用一些 count int,则使用 long 而不是 int,因为流在​​某些情况下会在 int 变量达到其限制的情况下停止。

尝试将 int t = inputRequest.read() 返回的 int 值传输到 fileoutputstream.write(t)。

inputRequest.available() 在您读取字节形式的输入流时不断减少,它返回流中可用的字节数。

通过这种方式,您可以上传大尺寸文件,而不会出现任何损坏。

如果有人需要有关此的更多详细信息,请留下您的评论。

于 2013-06-11T10:05:32.140 回答