A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 梁航斌 中级黑马   /  2013-4-9 12:51  /  2636 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 梁航斌 于 2013-4-10 20:02 编辑

PrintWriter用起来很方便,还能自动刷新,可是我自己写了个客户端上传图片到服务端的例子出问题了,图片大小变小了。我怀疑是pw.write(new String(buf,0,len));这里出的问题,我自己后来换了BufferedOutputStream就解决了,但是请问PrintWriter这个问题怎么解决呢,我加了flush()比不加的时候得出的图片要大几K,不是自动刷新吗?怎么差别就那么大呢?
上代码了
  1. import java.io.*;
  2. import java.net.*;
  3. //客户端
  4. class Client
  5. {
  6.         public static void main(String args[]) throws Exception{
  7.                 if(args.length!=1){
  8.                         System.out.println("一次仅能传送一张图片");
  9.                         return;
  10.                 }
  11.                 if(!args[0].endsWith(".jpg")){
  12.                         System.out.println("请注意图片格式,仅支持.jpg");
  13.                         return;
  14.                 }
  15.                 File file = new File(args[0]);
  16.                 if(file.length() > 1024*1024*5){
  17.                         System.out.println("文件不能超过5M");
  18.                         return;
  19.                 }
  20.                 System.out.println(args[0]);
  21.                 //建立Socket指向发送没标和端口
  22.                 Socket s = new Socket(InetAddress.getByName("192.168.1.4"),10000);
  23.                 //建立读取流对象,采用BufferedInputStream读取本地图片
  24.                 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
  25.                 //获取Socket对象的写入流,封装成PrintWriter提高效率
  26.                 PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
  27.                 //定义字节缓冲区
  28.                 byte []buf = new byte[1024];
  29.                 int len = 0;
  30.                 //循环读取写入到服务端
  31.                 while((len = bis.read(buf))!=-1){
  32.                         pw.write(new String(buf,0,len));
  33.                 }
  34.                 //告诉服务端这边写完了
  35.                 s.shutdownOutput();

  36.                 //获取Socket读取流,封装BufferedInputStream读取服务端返回的数据
  37.                 BufferedInputStream rbis = new BufferedInputStream(s.getInputStream());
  38.                 //因为就一句话,所以就不用循环了
  39.                 byte []b = new byte[1024];
  40.                 int num = rbis.read(b);
  41.                 System.out.println(new String(b,0,num));
  42.                 rbis.close();
  43.                 pw.close();
  44.                 s.close();
  45.         }
  46. }
复制代码
  1. import java.io.*;
  2. import java.net.*;
  3. class Server
  4. {
  5.         public static void main(String []args) throws Exception{
  6.                 //建立服务端对象,监听10000端口
  7.                 ServerSocket ss = new ServerSocket(10000);
  8.                 //循环控制客户端运行各自的线程
  9.                 while(true){
  10.                         //accept()是阻塞式的,因此不会陷入死循环
  11.                         Socket s = ss.accept();
  12.                         //开启对象各自的线程
  13.                         new Thread(new UpLoad(s)).start();
  14.                 }
  15.         }
  16. }
  17. class UpLoad implements Runnable
  18. {
  19.         private Socket s;
  20.         UpLoad(Socket s){
  21.                 this.s = s;
  22.         }
  23.         public void run(){
  24.                 try{
  25.                 //当客户端连接成功后服务端显示其ip
  26.                 String ip = s.getLocalAddress().getHostAddress();
  27.                 System.out.println(ip+"......连接成功");
  28.                 //定义计数器
  29.                 int count = 1;
  30.                 //定义一个File,用ip为图片命名,避免同名采用循环判断
  31.                 File file = new File("D:\\"+ip+".jpg");
  32.                 if(file.exists()){
  33.                         file = new File("D:\\"+ip+"("+(count++)+")"+".jpg");
  34.                 }
  35.                 //获取Socket对象的读取流,采用BufferedInputStream提高效率
  36.                 BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
  37.                 //写入流采用PrintWriter
  38.                 PrintWriter pw = new PrintWriter(new FileOutputStream(file),true);
  39.                 byte []buf = new byte[1024];
  40.                 int len = 0;
  41.                 while((len = bis.read(buf))!=-1){
  42.                         pw.write(new String(buf,0,len));
  43.                 }
  44.                 //告诉客户端这边读完了
  45.                 s.shutdownInput();

  46.                 //获取Socket对象的写入流,然后发送“上传成功”给客户端
  47.                 PrintWriter rpw = new PrintWriter(s.getOutputStream());
  48.                 rpw.write("上传成功");
  49.                 rpw.flush();
  50.                 rpw.close();
  51.                 pw.close();
  52.                 s.close();
  53.                 }
  54.                 catch(Exception e){
  55.                         
  56.                 }
  57.         }
  58. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

4 个回复

倒序浏览
在PrintWriter构造方法中,加上autoFlush标记,如果标记为true,只对println,printf,format三个方法有效,会自动刷新。write方法是不会自动刷新的。

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
黑马李超 发表于 2013-4-9 13:22
在PrintWriter构造方法中,加上autoFlush标记,如果标记为true,只对println,printf,format三个方法有效 ...

但是我也加了flush();啊,这咋回事?
回复 使用道具 举报
本帖最后由 贾振凯 于 2013-4-9 15:45 编辑

这个问题应该是跟编码有关,
API文档里有这么一句话:--------PrintWriter不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。

而音视频和图片文件里存储的都是原始字节,你在使用new String()方法时默认是要解码的,但是你的图片压根就没编码,解码从何谈起,在这里字节码应该就已经乱了
服务端用的字节流,读到的应该就是乱码了吧!至于刷新对文件大小的影响:我随便试了一下,刷新与不刷新都比原来的小且结果一样
  1. public class ReflectDemo {
  2. public static void main(String[] args) throws IOException {
  3. BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\Pier.jpg"));
  4. PrintWriter pw = new PrintWriter(new FileOutputStream("E:\\Pier2.jpg"),true);
  5. byte[] buf = new byte[1024];
  6. int len=0;
  7. while((len=bis.read(buf)) != -1){
  8. pw.write(new String(buf,0,len));
  9. pw.flush();
  10. }
  11. }
  12. }
复制代码
另外关于字节流读取音视频及图片文件的字节码的实现原理在毕来师第19天13个视频(自定义具有缓冲功能的字节流)有详细讲解!

以上是我的猜测,仅供参考哈呵呵!

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
贾振凯 发表于 2013-4-9 15:33
这个问题应该是跟编码有关,
API文档里有这么一句话:--------PrintWriter不包含用于写入原始字节的方法,对 ...

我也怀疑是编码问题,用BufferedWriter都没事。试了一下传txt,发现可以传,没乱码。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马