Java 中的文件拆分代码未按要求工作

File Splitting code in Java is not working as required

我试过下面的文件拆分代码,它可以工作,但不符合要求。 即一个 mp3 文件名 'song.mp3' 的大小为 2540KB,预期的块数(每个 100KB)为 25,但代码只给出了 12 个块,我不明白原因。

        public static void main(String[] args) throws IOException {

              File file = new File("song.mp3");

    FileInputStream fIn = new FileInputStream("song.mp3");
    FileOutputStream fOut = new FileOutputStream("song_0.mp3");
    int chunk_size = 1024 * 100;
    byte[] buff = new byte[chunk_size]; // 100KB file
    int i = 0;
    String file_name = file.getName();
    String file_name_base = file_name.substring(0, 
    file_name.lastIndexOf("."));
    while (fIn.read() != -1) {

        fIn.read(buff);
        int total_read = 0;
        total_read += chunk_size;
        long read_next_chunk = total_read;
        String file_name_new = file_name_base + "_" + i + ".mp3";
        File file_new = new File(file_name_base);
        i++;
        fOut = new FileOutputStream(file_name_new);
        fOut.write(buff);

        fIn.skip(total_read);// skip the total read part

    } // end of while loop

    fIn.close();
    fOut.close();

}

你的代码肯定行不通,至少是因为:
在每次迭代中,您读取 1 个字节并将其丢弃 while (fIn.read() != -1).
将循环更改为如下内容:

int bytesReadCounter;
while((bytesReadCounter = fIn.read(buff, 0, chunk_size)) > 0){
    .................................. 
    fOut.write(buff, 0, bytesReadCounter);
    ..................................
}

buff 中存储读取的字节数,在 bytesReadCounter 中存储读取的字节数。
然后,您从 buff 正好 bytesReadCounter 字节写入 fOut

编辑,使用此代码:

public static void main(String[] args) {
    File file = new File("song.mp3");

    FileInputStream fIn = null;
    try {
        fIn = new FileInputStream(file);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    int chunk_size = 1024 * 100;
    byte[] buff = new byte[chunk_size]; // 100KB file
    int i = 0;
    String file_name = file.getName();
    String file_name_base = file_name.substring(0, file_name.lastIndexOf("."));
    int bytesReadCounter;
    boolean hasMore = true;
    while (hasMore) {
        try {
            bytesReadCounter = fIn.read(buff, 0, chunk_size);
        } catch (IOException e) {
            e.printStackTrace();
            break;
        }

        hasMore = bytesReadCounter > 0;

        if (!hasMore)
            break;

        String file_name_new = file_name_base + "_" + i + ".mp3";
        File file_new = new File(file_name_new);

        FileOutputStream fOut = null;
        try {
            fOut = new FileOutputStream(file_new);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            break;
        }

        try {
            fOut.write(buff, 0, bytesReadCounter);
            fOut.close();
        } catch (IOException e) {
            e.printStackTrace();
            break;
        }

        i++;
    }

    try {
        fIn.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

我想立即推荐更新的 Path/Files 类.

以下代码未经测试,但有清晰的缓冲读数:

  • 顺序读取原文件
  • 循环零件
  • 使用缓冲区 (block) 写入一部分 - 这比单纯的 FileInputStream
  • 更快

所以:

public static void splitFile(String file) throws IOException {
    final long partSize = 100 * 1024;

    Path originalPath = Paths.get(file);
    if (Files.isReadable(originalPath)) {
        throw new FileNotFoundException("Is not a readable file: " + originalPath);
    }
    // Read the file:
    long totalSizeToRead = Files.size(originalPath);
    try (InputStream in = Files.newInputStream(originalPath)) {
        int partNo = 0;
        byte[] block = new byte[16 * 1024];
        // Write parts
        while (totalSizeToRead > 0) {
            // Write part
            ++partNo;
            Path partPath = Paths.get(String.format("%s-%03d.part", file, partNo));
            int sizeToReadInPart = partSize;
            if (totalSizeToRead < sizeToReadInPart) {
                sizeToReadInPart = (int) totalSizeToRead;
            }
            try (OutputStream out = Files.newOutputStream(partPath,
                                    StandardOpenOptions.REPLACE_EXISTING)) {
                // Write blocks of part
                while (sizeToReadInPart > 0) {
                    int toRead = Math.min(block.length, sizeToReadInPart);
                    int actuallyRead = in.read(block, 0, toRead);
                    sizeToReadInPart -= actuallyRead;
                    if (actuallyRead <= 0) {
                        break;
                    }
                    out.write(block, 0, actuallyRead);
                }
            }
            totalSizeToRead -= sizeToReadInPart;
        }
    }
}

这里的要点:

  • try-with-resource 自动关闭,即使出现 return/break/thrown 异常。
  • 我使用文件大小 (a Long) 和 int 作为缓冲区大小,需要注意一下。这也是一个冗余,给定 actuallyRead.
  • Java 按照惯例,对普通变量使用驼峰式而不是下划线。