我使用io scanner / System.out来复制文本文件。我尝试使用相同的技术来复制pdf,视频和图像文件。结果是文件被复制,但它们已损坏(无法打开它们)。此外,文件大小不等于原始文件大小。
码
import java.awt.Desktop;
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.util.Scanner;
public class ScannerTest {
public static void main(String[] args) throws IOException {
PrintStream out =System.out;
long start = System.currentTimeMillis();
copyFile(new File("H:\\a.pdf"), new File("H:\\b.pdf"));// 2 file input, output
System.setOut(out);
System.out.println(System.currentTimeMillis()-start);
}
static String text=null;
public static void copyFile(File input,File output) throws IOException{
//Scanner read file
Scanner in= new Scanner(new FileInputStream(input));
StringBuilder builder =new StringBuilder();
try {
while(in.hasNextLine()){
text=in.nextLine();
builder.append(text);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
in.close();
}
//System.out
try {
OutputStream outputStream = new FileOutputStream(output);
PrintStream printStream = new PrintStream(outputStream);
System.setOut(printStream);
System.out.println(new String(builder));
Desktop.getDesktop().open(output);
} catch (Exception e) {
e.printStackTrace();
}
}
}
p / s:不使用IO other。(例如:BufferedInput / OutputStream)
答案 0 :(得分:0)
有两个问题(至少):
您使用的nextLine()
会阅读下一个"\r\n"'
,'\n'
,'\r'
,'\u2028'
,'\u2029'
或'\u0085'
并丢弃它所发现的行分隔符(一个或两个字符)。因为你甚至没有使用append(text).append('\n')
我怀疑这会正确地复制多行文本,更不用说二进制文件,其中每个可能的行终止符可能有不同的含义。
您使用的Scanner
和StringBuilder
对二进制数据不安全。正如new Scanner(java.io.InputStream)
所述的文档:
使用底层平台的默认字符集将流中的字节转换为字符。
如果输入文件中的任何字节序列无效,例如UTF-8(这是一个常见的默认字符集)它默默地被一个通用的“无法读取输入”字符所取代。对于文本文件,这可能意味着'ä'被转换为' ',对于二进制文件,这可能导致整个文件无法使用。
如果你想复制任意(可能是二进制)文件,我建议不要冒任何机会并坚持使用byte[]
API。但是,在创建Scanner
和PrintStream
时,您也可以使用已知接受所有字节序列的字符集,如ISO-8859-1;你仍然需要避免使用压缩找到的行分隔符的line-API。
这应该可以解决问题:
import java.awt.Desktop;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
/**
* Created for http://stackoverflow.com/a/25351502/1266906
*/
public class CopyFile {
public static void main(String[] args) {
long start = System.currentTimeMillis();
copyFile(new File("H:\\a.pdf"), new File("H:\\b.pdf"));// 2 file input, output
System.out.println(System.currentTimeMillis() - start);
}
public static void copyFile(File input, File output) {
try {
try (FileInputStream inputStream = new FileInputStream(input);
OutputStream outputStream = new FileOutputStream(output)) {
byte[] buffer = new byte[4096];
do {
int readBytes = inputStream.read(buffer);
if (readBytes < 1) {
// end of file
break;
} else {
outputStream.write(buffer, 0, readBytes);
}
} while (true);
}
// Open result
Desktop.getDesktop().open(output);
} catch (Exception e) {
e.printStackTrace();
}
}
}
在Java 7之前,您需要使用try-finally:
public static void copyFile(File input, File output) {
try {
FileInputStream inputStream = new FileInputStream(input);
try {
OutputStream outputStream = new FileOutputStream(output);
try {
byte[] buffer = new byte[4096];
do {
int readBytes = inputStream.read(buffer);
if (readBytes < 1) {
// end of file
break;
} else {
outputStream.write(buffer, 0, readBytes);
}
} while (true);
} finally {
outputStream.close();
}
} finally {
inputStream.close();
}
// Open result
Desktop.getDesktop().open(output);
} catch (Exception e) {
e.printStackTrace();
}
}