黑马程序员技术交流社区

标题: 请教eclipse文件路径的问题(问题已解决)留作教训,供大家... [打印本页]

作者: cvnmklop    时间: 2014-11-10 17:19
标题: 请教eclipse文件路径的问题(问题已解决)留作教训,供大家...
本帖最后由 cvnmklop 于 2014-11-14 21:45 编辑

在编写TCP上传文件遇到文件路径问题,先贴代码请教高手
  1. class Server{
  2.         public static void main(String[] args)throws Exception{
  3.                
  4.                 ServerSocket serversocket = new ServerSocket(20000);
  5.                 Socket csocket = serversocket.accept();
  6.                 System.out.println(csocket.getInetAddress().getHostAddress()+" 连接成功");
  7.                
  8.                
  9.                 BufferedInputStream bisin = new BufferedInputStream(csocket.getInputStream());
  10.                 BufferedWriter bwout = new BufferedWriter(new OutputStreamWriter(csocket.getOutputStream()));
  11.                
  12.                 byte[] bufin = new byte[1024];
  13.                 bisin.read(bufin);//接收客户端上传的文件名
  14.                 String fileName = new String(bufin,0,bufin.length);
  15.                 fileName = "ServerRec/"+fileName;
  16. //                fileName = "F:\\"+fileName; 这样写也不行,下面创建文件却找不到路径
  17.                 System.out.println(fileName);//输出的结果是ServerRec/cilent.txt,但是下面创建文件却找不到路径
  18.                
  19.                         
  20.         
  21.                 byte[] buf = new byte[1024];
  22.                 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));//有异常FileNotFoundException: Invalid file path
  23. //                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("ServerRec/cilent.txt"));这样写创建文件成功
  24.                
  25.                 bwout.newLine();//向客户端发送服务端创建与客户端上传文件相同的名称的文件成功
  26.                 bwout.flush();
  27.                
  28.                 while(bisin.read(buf)!=-1){
  29.                         bos.write(buf);
  30.                         bos.flush();
  31.                 }
  32.                
  33.                
  34.                 bwout.write("上传成功");//反馈给客户端的信息
  35.                 bwout.flush();
  36.                
  37.                
  38.                 bos.close();
  39.                 csocket.close();
  40.         }
  41.                
  42. }
复制代码
fileName跟"ServerRec/cilent.txt"是一样的啊,为什么直接写就可以,用fileName就抛出异常
  1. class Client{
  2.         public static void main(String[] args)throws Exception{
  3.                
  4.                 Socket socket = new Socket("127.0.0.1",20000);
  5.                
  6.                 BufferedOutputStream bosout = new BufferedOutputStream(socket.getOutputStream());
  7.                 BufferedReader brin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  8.                
  9.                
  10.                 File sendFile  = new File("client.txt");//要上传的文件        
  11.                
  12.                 bosout.write(sendFile.getName().getBytes());//传送要上传的文件名给服务端
  13.                 bosout.flush();
  14.                
  15.                 brin.readLine();//获取服务端创建文件成功信号
  16.                                 
  17.                 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sendFile));
  18.                
  19.                 byte[] buf = new byte[1024];
  20.                 while(bis.read(buf)!=-1){
  21.                         bosout.write(buf);
  22.                         bosout.flush();
  23.                 }
  24.                 socket.shutdownOutput();//给服务端发送文件结束标记
  25.                
  26.                
  27.                 System.out.println(brin.readLine());
  28.                
  29.                 bis.close();
  30.                 socket.close();
  31.         }               
  32. }
复制代码
我的Eclipse文件结构如下
exam(工程名)

    |--src
          |--com.itheima
                |--Server
                |--Client
    |--ServerRec

                |--client.txt
    |--client.txt


顺便也给大家提个醒,readLine()只要没有读到换行符就一直处于阻塞状态。原先以为 while(readLine()!=null)是因为readLine()没有返回null才一直循环,程序停不下来。现在看来是因为readLine()是因为没有读到换行符一直处于阻塞状态才会一直等待并且readLine()只有读到换行符结束了才有返回结果。这个问题搞了一下午血的教训。望大家也注意。














作者: 王震阳老师    时间: 2014-11-12 13:16
你的文件路径有问题,在创建ServerRec默认应该在当前工程的根目录下。因此
  1. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));//有异常FileNotFoundException: Invalid file path
复制代码
这一行代码的错误与你写死还是用变量替换没关系。

答疑.jpg (146 KB, 下载次数: 10)

答疑.jpg

作者: cvnmklop    时间: 2014-11-12 15:21
就业指导-王震阳老师 发表于 2014-11-12 13:16
你的文件路径有问题,在创建ServerRec默认应该在当前工程的根目录下。因此这一行代码的错误与你写死还是用 ...

阳哥是我没写清楚,exam就是工程名。我的ServerRec就是直接建立在exam下的。
作者: 王震阳老师    时间: 2014-11-12 16:35
cvnmklop 发表于 2014-11-12 15:21
阳哥是我没写清楚,exam就是工程名。我的ServerRec就是直接建立在exam下的。

文件不可能找不到呀
作者: zhangyangLengen    时间: 2014-11-12 17:01
那个:File文件对象默认的目录是工程的根目录exam目录:
File sendFile  = new File("client.txt");//要上传的文件     
  而这个client.txt文件不是放在工程的根目录中,所以你要添加:ServerRec\\client.txt

而类加载器的默认的目录时bin目录
作者: 下一秒温存    时间: 2014-11-12 18:06
就业指导-王震阳老师 发表于 2014-11-12 13:16
你的文件路径有问题,在创建ServerRec默认应该在当前工程的根目录下。因此这一行代码的错误与你写死还是用 ...

阳哥,我的eclipse运行不了,网上教程都试过了还是不行,怎么整。。。。
作者: 王震阳老师    时间: 2014-11-12 22:10
下一秒温存 发表于 2014-11-12 18:06
阳哥,我的eclipse运行不了,网上教程都试过了还是不行,怎么整。。。。

我把你的代码考到我的Eclipse中是可以的,我估计你那里是存在低级错误了
作者: cvnmklop    时间: 2014-11-12 23:43
本帖最后由 cvnmklop 于 2014-11-12 23:45 编辑
zhangyangLengen 发表于 2014-11-12 17:01
那个:File文件对象默认的目录是工程的根目录exam目录:
File sendFile  = new File("client.txt");//要上 ...

我的工程根目录下就有client.txt文件的存在。请仔细看一下我的eclipse的文件结构。我要的是服务端把从客户端接收到的文件放在ServerRec目录下。但是eclipse的路径问题就是没明白错在哪。输出的fileName也是正确的结果是ServerRec/cilent.txt。在Server类的23行直接硬编码“ServerRec/cilent.txt"就行的通。还有你说的类加载器不明白,跟这个有什么联系吗
作者: zhangyangLengen    时间: 2014-11-13 08:56
eclipse的文件结构中的ServerRec文件夹是你手动创建的吗?

还有,从客户端往服务端进行写文件的名称,服务端接受到,想把此文件放到eclipse中的ServerRec目录中吗?
  fileName = "ServerRec/"+fileName;
   BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));

  你的代码是如上:
   但是服务器端保存的时候,必须要保证ServerRec,这个文件夹的路径必须存在,最好先用file.exist进行判断,如果不存在,就创建目录,然后将文件放进文件流中
作者: cvnmklop    时间: 2014-11-14 21:20
本帖最后由 cvnmklop 于 2014-11-14 23:30 编辑
zhangyangLengen 发表于 2014-11-13 08:56
eclipse的文件结构中的ServerRec文件夹是你手动创建的吗?

还有,从客户端往服务端进行写文件的名称,服务 ...

谢谢你的回答,ServerRec是我手动建立的。你的建议是正确,确实应该判断文件夹的存在。这个问题我自己今天解决了。
错误原因是服务端接收客户端文件名出了问题。服务端接收文件名的缓冲区定义了1024个字节。但是客户端传送的文件名达不到1024字节。那么就会在有效的字节后面空出来很多0。我在读缓冲区的时候String fileName = new String(bufin,0,bufin.length);是把整个缓冲区都读了进来,而缓冲区里有很多0结果就是把很多的0也读了进来。在内存中转换成字符串的时候java默认的编码是unicode,这样0就会被编码成了null(注意:这个null跟java的null不同,这个null的unicode编码值为\u0000,用System.out.print("\u0000")输出的结果就是空格),可想而知fileName里面有很多null即fileName="ServerRec/client.txtnullnullnull......null"。在创建文件的时候系统把多余的null也当作文件的路径了。这样就会报错FileNotFoundException: Invalid file path(无效文件路径)


这个查找之所以困难,甚至在debug下我也看不出来的问题在于
在调试时用打印语句查看System.out.println(fileName);输出语句打印了null形式上为空格,但是直观上看到的结果是ServerRec/client.txt这个正确的结果。在debug观察fileName的值时看到的情况跟打印语句的情况相同。这样就造成了困惑


从这次编写代码的教训,我知道了一定要读取有效的字节。read(byte[] by)一定要获得它读到的有效字节数。而不仅仅是为了读取。

谢谢大家的帮助,也要谢谢毕老师的视频,当我再次回顾视频的时候发现了这个严重的错误。
我把里面凡是涉及到的read(byte[] by)方法都进行了更改。
更改的代码如下:
  1. class Server{
  2.         public static void main(String[] args)throws Exception{
  3.                
  4.                 ServerSocket serversocket = new ServerSocket(20000);
  5.                 Socket csocket = serversocket.accept();
  6.                 System.out.println(csocket.getInetAddress().getHostAddress()+" 连接成功");
  7.                
  8.                 BufferedInputStream bisin = new BufferedInputStream(csocket.getInputStream());
  9.                 BufferedWriter bwout = new BufferedWriter(new OutputStreamWriter(csocket.getOutputStream()));
  10.                
  11.                 byte[] bufin = new byte[1024];
  12.                
  13.                 int fileNameLen = bisin.read(bufin);//接收客户端上传的文件名
  14.                 String fileName = new String(bufin,0,fileNameLen);
  15.                 //String fileName = new String(bufin,0,bufin.length);这样写是错误的,因为当文件名小于1024字节会出现,String里面会接收到很多Null,系统会把Null也当作路径,这样就会报错Invalid file path
  16.                
  17.                 fileName = "ServerRec/"+fileName;
  18.                 System.out.println(fileName);
  19.                
  20.                 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));

  21.                 bwout.newLine();//向客户端发送服务端创建与客户端上传文件相同的名称的文件成功
  22.                 bwout.flush();
  23.                
  24.                 int len  = 0;
  25.                 byte[] buf = new byte[1024];
  26.                 while((len=bisin.read(buf))!=-1){
  27.                         bos.write(buf,0,len);
  28.                         bos.flush();
  29.                 }
  30.                
  31.                
  32.                 bwout.write("上传成功");//反馈给客户端的信息
  33.                 bwout.flush();
  34.                
  35.                 bos.close();
  36.                 csocket.close();
  37.         }
  38.                
  39. }
复制代码

  1. class Client{
  2.         public static void main(String[] args)throws Exception{
  3.                
  4.                 Socket socket = new Socket("127.0.0.1",20000);
  5.                
  6.                 BufferedOutputStream bosout = new BufferedOutputStream(socket.getOutputStream());
  7.                 BufferedReader brin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  8.                         
  9.                 File sendFile  = new File("client.txt");//要上传的文件        
  10.                
  11.                 bosout.write(sendFile.getName().getBytes());//传送要上传的文件名给服务端
  12.                 bosout.flush();
  13.                
  14.                 brin.readLine();//获取服务端创建文件成功信号
  15.                                 
  16.                 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sendFile));
  17.                
  18.                 byte[] buf = new byte[1024];
  19.                 int len =0;
  20.                 while((len =bis.read(buf))!=-1){
  21.                         bosout.write(buf,0,len);
  22.                         bosout.flush();
  23.                 }
  24.                 socket.shutdownOutput();//给服务端发送文件结束标记
  25.                         
  26.                 System.out.println(brin.readLine());
  27.                
  28.                 bis.close();
  29.                 socket.close();
  30.         }               
  31. }
复制代码






作者: cvnmklop    时间: 2014-11-14 21:52
就业指导-王震阳老师 发表于 2014-11-12 16:35
文件不可能找不到呀

谢谢阳哥,问题已解决。是服务端出了问题,
具体如下
http://bbs.itheima.com/forum.php ... 194&pid=1074326
作者: cvnmklop    时间: 2014-11-14 23:32
就业指导-王震阳老师 发表于 2014-11-12 13:16
你的文件路径有问题,在创建ServerRec默认应该在当前工程的根目录下。因此这一行代码的错误与你写死还是用 ...

阳哥,刚刚发给你的那个问题的解决有些瑕疵,现已更正。
http://bbs.itheima.com/forum.php ... 194&pid=1074326
作者: zhangyangLengen    时间: 2014-11-15 09:37
嗯,不错,就是要注意读取的有效的字节。自己也学习了。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2