【问题标题】:FileOutputStream writing out 0 bytes [duplicate]FileOutputStream写出0个字节[重复]
【发布时间】:2017-11-10 08:51:50
【问题描述】:

我正在尝试通过 Java 套接字将文件从一个程序发送到另一个程序。我的代码基于this question问题是在托管服务器的 Ubuntu 机器上,发送过来的文件大小为 0 字节。该代码已在我的 Windows 笔记本电脑上的本地连接上运行,所以可能 问题出在与远程连接有关吗?

服务器代码:

int g = Integer.parseInt(in.readLine());
if(g > -1) {
    InputStream fIn = client.getInputStream();
    for(int i = 0; i < g; i++) {
        String name = in.readLine();
        byte[] bytes = new byte[16*1024];
        File f = new File("plugins/" + name + ".jar");
        if(!f.exists()) f.createNewFile();
        FileOutputStream fOut = new FileOutputStream(f);
        int count;
        while ((count = fIn.read(bytes)) >= 0) {
            fOut.write(bytes, 0, count);
        }
        fOut.flush();
        fOut.close();
    }
    System.out.println("[" + client.getRemoteSocketAddress().toString() + "] added " + g + " new plugins.");
    client.close();
}else{
    client.close();
}

客户端代码:

JFileChooser fd = new JFileChooser("C:\\");                         
fd.setFileSelectionMode(JFileChooser.FILES_ONLY);
fd.setMultiSelectionEnabled(true);
fd.setFileFilter(new FileNameExtensionFilter(null,"jar"));
int r = fd.showOpenDialog(null);
if(r == JFileChooser.APPROVE_OPTION) {
    File[] files = fd.getSelectedFiles();
    OutputStream fOut = sock.getOutputStream();
    out.println(files.length);
    for(File f : files) {
        out.println(f.getName().split("\\.")[0]);
        byte[] bytes = new byte[16 * 1024];
        FileInputStream fIn = new FileInputStream(f);
        int count;
        while ((count = fIn.read(bytes)) >= 0) {
            fOut.write(bytes, 0, count);
        }
        fIn.close();
    }
}else{
    out.println(-1);
}
sock.close();

【问题讨论】:

  • client 是什么对象?第一个元素/行是文件数。添加读取文件数量的部分?您的代码中存在不同的问题:流中没有分隔符告诉服务器文件的所有字节都已读取并且新文件开始。您的异常/资源处理。如果发生异常,您可能不会关闭所有流,这可能会成为服务器端真正的大问题。
  • @andih 客户端是一个套接字。对于连接到服务器的每个新客户端,套接字都会传递给一个线程,因此“服务器”代码嵌套在 run() 中。是的,第一行读取文件的数量,请参阅编辑。
  • @andih 也许您可以发布添加分隔符的答案?此外,我处理给定代码之外的异常。我的异常处理怎么会成为服务器端的“真正的大问题”?完成协议后,双方终止连接。如果在关闭客户端套接字时抛出服务器端错误,则线程结束。基本上,如果似乎有问题,那么双方都会终止。
  • exists()/createNewFile() 部分完全是浪费时间和空间。 new FileOutputStream() 然后必须删除该文件并创建一个新文件。不要编写无意义的代码。三个系统调用都可以做。
  • @EJP 我不明白为什么这是完全重复的。通过套接字发送多个文件是问题的一方面。网上有不同的教程/示例如何通过套接字发送多个文件。 “主要”问题是为什么服务器端的文件大小为 0 字节。

标签: java sockets ubuntu server fileoutputstream


【解决方案1】:

正如 cmets 中所说,您的代码中存在不同的问题。

要识别单个文件的结尾,您只需在文件名后添加文件大小,用分号分隔即可;

out.println(f.getName().split("\\.")[0] + "; size" + f.length());

在服务器端,您累积读取/写入的文件大小 stop read 文件的内容关闭它并读取下一行(文件名/文件大小)。

正如 cmets 中所说,存在不同的问题。 您使用 fInfOut 不清楚它们是如何定义的。 在客户端,您使用fOut,而 Socket OutputStream 被命名为“out”。 服务器端类似的事情。您从in 读取文件的数量,但之后您从 Socket 获取 InputStream(再次?)并将其用作fIn。取决于您的 in,这可能会也可能不会。

还从InputStream 中通过readLine 读取一行,并且二进制内容也不是那么简单。在我的示例代码中,我使用了DataInputStream,即使readLine 方法已被弃用。

该示例还使用“try with resources”语法来确保在发生异常时关闭所有资源(流、套接字)。

示例没有显示如何处理服务器端的文件大小这取决于您。

该示例完全可以在单台机器上运行,并展示了如何根据您的代码通过套接字复制单个文件。

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class ClientServerSocketExample {

    private static class Server {

        public void run() throws IOException {

            try (ServerSocket serverSocket = new ServerSocket(41000, 10, InetAddress.getLocalHost())) {
                try (Socket client = serverSocket.accept()) {

                    try (DataInputStream in = new DataInputStream(client.getInputStream())) {

                        int g = Integer.parseInt(in.readLine());

                        if(g > -1) {
                            for(int i = 0; i < g; i++) {
                                String[] filenameAndSize = in.readLine().split(";");
                                String name = filenameAndSize[0];
                                byte[] bytes = new byte[16*1024];
                                File f = new File("/tmp/" + name + ".jar");
                                if(!f.exists()) f.createNewFile();
                                try (FileOutputStream fOut = new FileOutputStream(f)) {
                                    int count;
                                    while ((count = in.read(bytes)) >= 0) {
                                        fOut.write(bytes, 0, count);
                                    }
                                    fOut.flush();
                                }
                            }
                            System.out.println("[" + client.getRemoteSocketAddress().toString() + "] added " + g + " new plugins.");


                        }
                    }
                }
            }
        }

    }

    private static class Client {

        public void run() throws IOException {
            try (Socket socket = new Socket()) {
                socket.connect(new InetSocketAddress(InetAddress.getLocalHost(), 41000) );

                sendFiles(socket);
            }
        }

        private static void sendFiles(Socket sock) throws IOException {
            File[] files = new File[]{new File("some.jar")}; 
            OutputStream fOut = sock.getOutputStream();
            PrintStream out = new PrintStream(fOut);

            out.println(files.length);
            for(File f : files) {
                out.println(f.getName().split("\\.")[0] + "; size" + f.length());

                byte[] bytes = new byte[16 * 1024];
                try (FileInputStream fIn = new FileInputStream(f)) {
                    int count;
                    while ((count = fIn.read(bytes)) >= 0) {
                        out.write(bytes, 0, count);
                    }
                    out.flush();
                }
            }
        }


    }



    public static void main(String ... args) throws IOException, InterruptedException {
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    new Server().run();
                } catch (IOException ioe) {
                    System.out.println(ioe);
                }


            }

        }).start();

        System.out.println("Waiting for the Server to come up");
        Thread.sleep(500);

        new Client().run();
    }

}

当客户端发送\r 作为换行符并且文件以\n 开头时,此解决方案可能存在问题。服务器可能会将\n 视为行分隔符的一部分,并且文件将被损坏(将丢失一个字节)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-19
    • 1970-01-01
    • 2019-09-06
    相关资源
    最近更新 更多