文件传输基础~Java I/O 流。
文章目录
文件的编码。
eg. 文件内容都是“移动”。
UTF-8 一个中文占 3 个字节。
ANSI 一个中文占 2 个字节。
package com.geek.encode;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.SortedMap;
public class EncodeDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
// TODO Auto-generated method stub
String s = "幕课 ABC";
byte[] bytes1 = s.getBytes();
for (byte b : bytes1) {
// 把字节(转换成了 int)以 16 进制的方式显示。
System.out.print(Integer.toHexString(b) + " ");
// System.out.println(Integer.toHexString(b & 0xff));
// ffffffe5 ffffffb9 ffffff95 ffffffe8 ffffffaf ffffffbe 20 41 42 43
}
System.out.println();
// gbk 编码中文占用 2 个字节。英文占用 1 个字节。
byte[] bytes2 = s.getBytes("gbk");
for (byte aByte : bytes2) {
System.out.print(aByte + " ");
// -60 -69 -65 -50 32 65 66 67
}
System.out.println();
// utf-8 编码中文占用 3 个字节。英文占用 1 个字节。
byte[] bytes3 = s.getBytes(StandardCharsets.UTF_8);
for (byte aByte : bytes3) {
System.out.print(aByte + " ");
// -27 -71 -107 -24 -81 -66 32 65 66 67
}
System.out.println();
// Java 是双字节编码。utf-16be。
// utf-16be 编码中文占用 2 个字节。英文占用 2 个字节。
byte[] bytes4 = s.getBytes(StandardCharsets.UTF_16BE);
for (byte aByte : bytes4) {
System.out.print(aByte + " ");
// 94 85 -117 -2 0 32 0 65 0 66 0 67
}
System.out.println();
// 当字节序列以某种编码晨,想把 ta 转换为字符串,
// 也必须使用该编码方式,否则出现乱码。
String string = new String(bytes4);// 使用项目默认编码。
System.out.println("string = " + string);
// string = ^U�� A B C
String string2 = new String(bytes4, "utf-16be");// 使用项目默认编码。
System.out.println("string2 = " + string2);
// string2 = 幕课 ABC
System.out.println();
/**
* 文本文件 就是字节序列。
* 可以是任意编码的字节序列。
* 如果我们在中文机器中直接创建文本文件,只认识 ansi 编码。
* 从其他位置来的文件,都认识。eg. 复制过来的文件。
*/
SortedMap<String, Charset> stringCharsetSortedMap = Charset.availableCharsets();
System.out.println("stringCharsetSortedMap = " + stringCharsetSortedMap);
// stringCharsetSortedMap = {Big5=Big5, Big5-HKSCS=Big5-HKSCS, CESU-8=CESU-8, EUC-JP=EUC-JP, EUC-KR=EUC-KR, GB18030=GB18030, GB2312=GB2312, GBK=GBK, IBM-Thai=IBM-Thai, IBM00858=IBM00858, IBM01140=IBM01140, IBM01141=IBM01141, IBM01142=IBM01142, IBM01143=IBM01143, IBM01144=IBM01144, IBM01145=IBM01145, IBM01146=IBM01146, IBM01147=IBM01147, IBM01148=IBM01148, IBM01149=IBM01149, IBM037=IBM037, IBM1026=IBM1026, IBM1047=IBM1047, IBM273=IBM273, IBM277=IBM277, IBM278=IBM278, IBM280=IBM280, IBM284=IBM284, IBM285=IBM285, IBM290=IBM290, IBM297=IBM297, IBM420=IBM420, IBM424=IBM424, IBM437=IBM437, IBM500=IBM500, IBM775=IBM775, IBM850=IBM850, IBM852=IBM852, IBM855=IBM855, IBM857=IBM857, IBM860=IBM860, IBM861=IBM861, IBM862=IBM862, IBM863=IBM863, IBM864=IBM864, IBM865=IBM865, IBM866=IBM866, IBM868=IBM868, IBM869=IBM869, IBM870=IBM870, IBM871=IBM871, IBM918=IBM918, ISO-2022-CN=ISO-2022-CN, ISO-2022-JP=ISO-2022-JP, ISO-2022-JP-2=ISO-2022-JP-2, ISO-2022-KR=ISO-2022-KR, ISO-8859-1=ISO-8859-1, ISO-8859-13=ISO-8859-13, ISO-8859-15=ISO-8859-15, ISO-8859-2=ISO-8859-2, ISO-8859-3=ISO-8859-3, ISO-8859-4=ISO-8859-4, ISO-8859-5=ISO-8859-5, ISO-8859-6=ISO-8859-6, ISO-8859-7=ISO-8859-7, ISO-8859-8=ISO-8859-8, ISO-8859-9=ISO-8859-9, JIS_X0201=JIS_X0201, JIS_X0212-1990=JIS_X0212-1990, KOI8-R=KOI8-R, KOI8-U=KOI8-U, Shift_JIS=Shift_JIS, TIS-620=TIS-620, US-ASCII=US-ASCII, UTF-16=UTF-16, UTF-16BE=UTF-16BE, UTF-16LE=UTF-16LE, UTF-32=UTF-32, UTF-32BE=UTF-32BE, UTF-32LE=UTF-32LE, UTF-8=UTF-8, windows-1250=windows-1250, windows-1251=windows-1251, windows-1252=windows-1252, windows-1253=windows-1253, windows-1254=windows-1254, windows-1255=windows-1255, windows-1256=windows-1256, windows-1257=windows-1257, windows-1258=windows-1258, windows-31j=windows-31j, x-Big5-HKSCS-2001=x-Big5-HKSCS-2001, x-Big5-Solaris=x-Big5-Solaris, x-euc-jp-linux=x-euc-jp-linux, x-EUC-TW=x-EUC-TW, x-eucJP-Open=x-eucJP-Open, x-IBM1006=x-IBM1006, x-IBM1025=x-IBM1025, x-IBM1046=x-IBM1046, x-IBM1097=x-IBM1097, x-IBM1098=x-IBM1098, x-IBM1112=x-IBM1112, x-IBM1122=x-IBM1122, x-IBM1123=x-IBM1123, x-IBM1124=x-IBM1124, x-IBM1166=x-IBM1166, x-IBM1364=x-IBM1364, x-IBM1381=x-IBM1381, x-IBM1383=x-IBM1383, x-IBM300=x-IBM300, x-IBM33722=x-IBM33722, x-IBM737=x-IBM737, x-IBM833=x-IBM833, x-IBM834=x-IBM834, x-IBM856=x-IBM856, x-IBM874=x-IBM874, x-IBM875=x-IBM875, x-IBM921=x-IBM921, x-IBM922=x-IBM922, x-IBM930=x-IBM930, x-IBM933=x-IBM933, x-IBM935=x-IBM935, x-IBM937=x-IBM937, x-IBM939=x-IBM939, x-IBM942=x-IBM942, x-IBM942C=x-IBM942C, x-IBM943=x-IBM943, x-IBM943C=x-IBM943C, x-IBM948=x-IBM948, x-IBM949=x-IBM949, x-IBM949C=x-IBM949C, x-IBM950=x-IBM950, x-IBM964=x-IBM964, x-IBM970=x-IBM970, x-ISCII91=x-ISCII91, x-ISO-2022-CN-CNS=x-ISO-2022-CN-CNS, x-ISO-2022-CN-GB=x-ISO-2022-CN-GB, x-iso-8859-11=x-iso-8859-11, x-JIS0208=x-JIS0208, x-JISAutoDetect=x-JISAutoDetect, x-Johab=x-Johab, x-MacArabic=x-MacArabic, x-MacCentralEurope=x-MacCentralEurope, x-MacCroatian=x-MacCroatian, x-MacCyrillic=x-MacCyrillic, x-MacDingbat=x-MacDingbat, x-MacGreek=x-MacGreek, x-MacHebrew=x-MacHebrew, x-MacIceland=x-MacIceland, x-MacRoman=x-MacRoman, x-MacRomania=x-MacRomania, x-MacSymbol=x-MacSymbol, x-MacThai=x-MacThai, x-MacTurkish=x-MacTurkish, x-MacUkraine=x-MacUkraine, x-MS932_0213=x-MS932_0213, x-MS950-HKSCS=x-MS950-HKSCS, x-MS950-HKSCS-XP=x-MS950-HKSCS-XP, x-mswin-936=x-mswin-936, x-PCK=x-PCK, x-SJIS_0213=x-SJIS_0213, x-UTF-16LE-BOM=x-UTF-16LE-BOM, X-UTF-32BE-BOM=X-UTF-32BE-BOM, X-UTF-32LE-BOM=X-UTF-32LE-BOM, x-windows-50220=x-windows-50220, x-windows-50221=x-windows-50221, x-windows-874=x-windows-874, x-windows-949=x-windows-949, x-windows-950=x-windows-950, x-windows-iso2022jp=x-windows-iso2022jp}
}
}
File 类。
package com.geek.file;
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) {
String separator = File.separator;
System.out.println("separator = " + separator);
// /
String pathSeparator = File.pathSeparator;
System.out.println("pathSeparator = " + pathSeparator);
// :
char separatorChar = File.separatorChar;
System.out.println("separatorChar = " + separatorChar);
// /
char pathSeparatorChar = File.pathSeparatorChar;
System.out.println("pathSeparatorChar = " + pathSeparatorChar);
// ;
// 构造方法。
File file = new File("/home/geek/geek/javaio/test");
boolean exists = file.exists();
System.out.println("exists = " + exists);
if (!file.exists()) {
boolean mkdir = file.mkdir();
System.out.println("mkdir = " + mkdir);
} else {
boolean delete = file.delete();
System.out.println("delete = " + delete);
}
// 构造方式 2。
// new File("home/geek/geek/javaio/txt/日记.txt");
File file1 = new File("/home/geek/geek/javaio/", "日记.txt");
if (!file1.exists()) {
try {
file1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
} else {
file1.delete();
}
// 常用 api。
System.out.println("file = " + file);// file = /home/geek/geek/javaio/test
String absolutePath = file.getAbsolutePath();
System.out.println(absolutePath);// /home/geek/geek/javaio/test
String name = file.getName();
System.out.println(name);
String parent = file.getParent();
System.out.println(parent);
}
}
package com.geek.file;
import java.io.File;
public class FileUtils {
/**
* 列出指定目录下(包括其子目录)的所有文件。
*
* @param dir
*/
public static void listDirectory(File dir) {
// 目录不存在。
if (!dir.exists()) {
throw new RuntimeException("目录" + dir + "不存在。");
}
// 不是目录。
if (!dir.isDirectory()) {
throw new RuntimeException(dir + "不是目录。");
}
String[] list = dir.list();// 字符串数组。
assert list != null;
for (String string : list) {
System.out.println(dir + "/" + string);
}
// 如果要遍历子目录下的内容就要构造成 File 对象做递归操作。File 提供了直接返回 File 对象的 api。
File[] files = dir.listFiles();// 返回的是直接子目录的对象。
if (files != null && files.length > 0) {
for (File file : files) {
// System.out.println(file);
if (file.isDirectory()) {
// 递归。
listDirectory(file);
} else {
System.out.println("file = " + file);
}
}
}
}
}
package com.geek.file;
import java.io.File;
public class FileUtilsTest {
public static void main(String[] args) {
FileUtils.listDirectory(new File("/home/geek/IdeaProjects/geek_file/geek-file"));
}
}
RandomAccessFile。
常用:多线程下载文件。
package com.geek;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
public class RandomAccessFileDemo {
// RandomAccessFile。Java 提供的对文件内容的访问,既可以读文件也可以写文件。
// RandomAccessFile 支持随机访问文件,可以访问文件任意位置。
// Java 文件模型。
// 在硬盘上的文件是 byte byte byte 存储的。是数据的集合。
// 打开文件。
// 两种模式。rw 读写。r 只读。
// 文件指针。打开文件时指针在开头。
// 写文件。
// raf.write(int);。只写一个字节(后 8 位),同时指针指向下一个位置,准备再次写入。
// 读方法。
// int b = raf.read();。
// 文件操作完毕一定要关闭。Oracle 官方文档说明。
public static void main(String[] args) throws IOException {
// 创建文件夹。
File demo = new File("demo");
if (!demo.exists()) {
demo.mkdir();
}
// 创建文件。
File file = new File(demo, "raf.dat");
if (!file.exists()) {
file.createNewFile();
}
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
// 指针的位置。
long filePointer = randomAccessFile.getFilePointer();
System.out.println(filePointer);// 0。
randomAccessFile.write('A');
// write(); 只写入一个字节。
// 一个 char 2 字节。所以先写入 A 的后 8 位。
System.out.println(randomAccessFile.getFilePointer());// 1
randomAccessFile.write('B');
System.out.println(randomAccessFile.getFilePointer());// 2
int i = 0x7fffffff;// Java 最大整数。
// 用 write() 方法,每次只能写一个字节,写入 i 要写 4 次。
randomAccessFile.write(i >>> 24);// 高八位。
randomAccessFile.write(i >>> 16);
randomAccessFile.write(i >>> 8);
randomAccessFile.write(i);
System.out.println(randomAccessFile.getFilePointer());// 6
// 直接写入 int。
randomAccessFile.writeInt(i);
String s = "中";
byte[] gbk = s.getBytes("gbk");
randomAccessFile.write(gbk);
System.out.println(randomAccessFile.length());// 12
// 读文件,必须把指针移到头部。
randomAccessFile.seek(0);
// 一次性读取。
byte[] buf = new byte[(int) randomAccessFile.length()];
randomAccessFile.read(buf);
System.out.println(Arrays.toString(buf));
// [65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
String s1 = Arrays.toString(buf);
System.out.println("s1 = " + s1);
// s1 = [65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
for (byte b : buf) {
System.out.print(Integer.toHexString(b & 0xff) + " ");
// 41 42 7f ff ff ff 7f ff ff ff d6 d0
}
randomAccessFile.close();
}
}
IO 流。(输入流、输出流)。
字节流。
InputSream、OutputStream。
InputSream 抽象了应用程序读取数据的方式。
OutputStream 抽象了应用程序写出数据的方式。
EOF。
EOF = End。读到 -1 就到结尾。
FileInputStream 具体实现了在文件上的读取数据。
package com.geek.io;
import java.io.*;
public class IOUtil {
/**
* 读取文件内容,按照 16 进制输出到控制台。
*/
// IOUtilTest。
public static void printHex(String fileName) throws IOException {
// 把文件作为字节流进行读操作。
FileInputStream inputStream = new FileInputStream(fileName);
int b;
int i = 1;
while ((b = inputStream.read()) != -1) {
if (b < 0xf) {
// 单位数前补 0。
System.out.print("0");
}
System.out.print(Integer.toHexString(b) + " ");
if (i+- % 10 == 0) {
System.out.println();
}
}
inputStream.close();
}
}
- 测试。
package com.geek.io;
import java.io.IOException;
public class IOUtilTest {
public static void main(String[] args) {
try {
IOUtil.printHex("/home/geek/IdeaProjects/geek_file/geek-file/src/com/geek/io/IOUtil.java");
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.geek.io;
import java.io.*;
public class IOUtil {
/**
* 读取文件内容。字节数组。按照 16 进制输出到控制台。
*
* @param fileName
* @throws IOException
*/
// IOUtilTest02。
public static void printHexByByteArray(String fileName) throws IOException {
FileInputStream inputStream = new FileInputStream(fileName);
byte[] buf = new byte[8 * 1024];
// 从 inputStream 中批量读取字节,放入到 buf 字节数组中,
// 从第 0 个位置开始,最多放 buf.length 个。
// 返回的是读到的字节个数。
/*
int read = inputStream.read(buf, 0, buf.length);// 一次性读完,说明字节数组足够大。
int j = 1;
for (int i = 0; i < read; i++) {
if (buf[i] <= 0xf) {
System.out.print("0");// 补 0。
}
System.out.print(Integer.toHexString(buf[i]) + " ");
if (j+- % 10 == 0) {
System.out.println();
}
}
*/
int bytes = 0;
int j = 0;
while ((bytes = inputStream.read(buf, 0, buf.length)) != -1) {
for (int i = 0; i < bytes; i++) {
System.out.print(Integer.toHexString(buf[i] & 0xff) + " ");
if (j+- % 10 == 0) {
System.out.println();
}
}
}
}
}
package com.geek.io;
import java.io.IOException;
public class IOUtilTest02 {
public static void main(String[] args) {
try {
IOUtil.printHexByByteArray("/home/geek/IdeaProjects/geek_file/geek-file/src/com/geek/io/IOUtil.java");
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileOutputStream 具体实现了在文件上的写入数据。
package com.geek.out;
import com.geek.io.IOUtil;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutDemo {
public static void main(String[] args) throws IOException {
// 如果不存在,则直接创建。如果存在,删除后创建。
FileOutputStream fileOutputStream = new FileOutputStream("geek-file/out.dat");
fileOutputStream.write('A');// 写出 A 字符的低 8 位。
fileOutputStream.write('B');// 写出 B 字符的低 8 位。
int a = 10;
// write(); 方法只能写出低 8 位。写一个 int 需要写 4 次。
fileOutputStream.write(a >>> 24);
fileOutputStream.write(a >>> 16);
fileOutputStream.write(a >>> 8);
fileOutputStream.write(a);
byte[] gbk = "中国".getBytes("utf-8");
fileOutputStream.write(gbk);
fileOutputStream.close();
IOUtil.printHex("geek-file/out.dat");
}
}
- copy。
package com.geek.io;
import java.io.*;
public class IOUtil {
/**
* 读取文件内容,按照 16 进制输出到控制台。
*/
// IOUtil
public static void printHex(String fileName) throws IOException {
// 把文件作为字节流进行读操作。
FileInputStream inputStream = new FileInputStream(fileName);
int b;
int i = 1;
while ((b = inputStream.read()) != -1) {
if (b < 0xf) {
// 单位数前补 0。
System.out.print("0");
}
System.out.print(Integer.toHexString(b) + " ");
if (i+- % 10 == 0) {
System.out.println();
}
}
inputStream.close();
}
/**
* 读取文件内容。字节数组。按照 16 进制输出到控制台。
*
* @param fileName
* @throws IOException
*/
// IOUtilTest02。
public static void printHexByByteArray(String fileName) throws IOException {
FileInputStream inputStream = new FileInputStream(fileName);
byte[] buf = new byte[8 * 1024];
// 从 inputStream 中批量读取字节,放入到 buf 字节数组中,
// 从第 0 个位置开始,最多放 buf.length 个。
// 返回的是读到的字节个数。
/*
int read = inputStream.read(buf, 0, buf.length);// 一次性读完,说明字节数组足够大。
int j = 1;
for (int i = 0; i < read; i++) {
if (buf[i] <= 0xf) {
System.out.print("0");// 补 0。
}
System.out.print(Integer.toHexString(buf[i]) + " ");
if (j+- % 10 == 0) {
System.out.println();
}
}
*/
int bytes = 0;
int j = 0;
while ((bytes = inputStream.read(buf, 0, buf.length)) != -1) {
for (int i = 0; i < bytes; i++) {
System.out.print(Integer.toHexString(buf[i] & 0xff) + " ");
if (j+- % 10 == 0) {
System.out.println();
}
}
}
}
// CopyTest。
public static void copyFile(File srcFile, File destFile) throws IOException {
if (!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在。");
}
if (!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件。");
}
FileInputStream inputStream = new FileInputStream(srcFile);
FileOutputStream outputStream = new FileOutputStream(destFile);
byte[] buf = new byte[8 * 1024];
int b;
while ((b = inputStream.read(buf, 0, buf.length)) != -1) {
outputStream.write(buf, 0, b);
outputStream.flush();
}
outputStream.close();
inputStream.close();
}
}
- 测试。
package com.geek.out;
import com.geek.io.IOUtil;
import java.io.File;
import java.io.IOException;
public class CopyTest {
public static void main(String[] args) {
try {
IOUtil.copyFile(new File("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), new File("/home/geek/IdeaProjects/geek_file/geek-file/geek01.txt"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
DataOutputStream、DataInputStream。
对流的扩展。更加方便的读取 int, long,字符等类型的数据。
package com.geek.io;
import java.io.*;
public class IOUtil {
/**
* 读取文件内容,按照 16 进制输出到控制台。
*/
// IOUtil
public static void printHex(String fileName) throws IOException {
// 把文件作为字节流进行读操作。
FileInputStream inputStream = new FileInputStream(fileName);
int b;
int i = 1;
while ((b = inputStream.read()) != -1) {
if (b < 0xf) {
// 单位数前补 0。
System.out.print("0");
}
System.out.print(Integer.toHexString(b) + " ");
if (i+- % 10 == 0) {
System.out.println();
}
}
inputStream.close();
}
/**
* 读取文件内容。字节数组。按照 16 进制输出到控制台。
*
* @param fileName
* @throws IOException
*/
// IOUtilTest02。
public static void printHexByByteArray(String fileName) throws IOException {
FileInputStream inputStream = new FileInputStream(fileName);
byte[] buf = new byte[8 * 1024];
// 从 inputStream 中批量读取字节,放入到 buf 字节数组中,
// 从第 0 个位置开始,最多放 buf.length 个。
// 返回的是读到的字节个数。
/*
int read = inputStream.read(buf, 0, buf.length);// 一次性读完,说明字节数组足够大。
int j = 1;
for (int i = 0; i < read; i++) {
if (buf[i] <= 0xf) {
System.out.print("0");// 补 0。
}
System.out.print(Integer.toHexString(buf[i]) + " ");
if (j+- % 10 == 0) {
System.out.println();
}
}
*/
int bytes = 0;
int j = 0;
while ((bytes = inputStream.read(buf, 0, buf.length)) != -1) {
for (int i = 0; i < bytes; i++) {
System.out.print(Integer.toHexString(buf[i] & 0xff) + " ");
if (j+- % 10 == 0) {
System.out.println();
}
}
}
}
/**
* 文件 copy。字节批量读取。
*
* @param srcFile
* @param destFile
* @throws IOException
*/
// CopyTest。
public static void copyFile(File srcFile, File destFile) throws IOException {
if (!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在。");
}
if (!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件。");
}
FileInputStream inputStream = new FileInputStream(srcFile);
FileOutputStream outputStream = new FileOutputStream(destFile);
byte[] buf = new byte[8 * 1024];
int b;
while ((b = inputStream.read(buf, 0, buf.length)) != -1) {
outputStream.write(buf, 0, b);
outputStream.flush();
}
outputStream.close();
inputStream.close();
}
/**
* 进行文件拷贝,利用带缓冲的字节流。
*
* @param srcFile
* @param destFile
*/
// CopyTest02。
public static void copyFileByBuffer(File srcFile, File destFile) throws IOException {
if (!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在。");
}
if (!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件。");
}
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFile));
int c;
while ((c = bufferedInputStream.read()) != -1) {
bufferedOutputStream.write(c);
bufferedOutputStream.flush();// 刷新缓冲区。
}
bufferedOutputStream.close();
bufferedInputStream.close();
}
}
package com.geek.dataIO;
import com.geek.io.IOUtil;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class DataInStreamDemo {
public static void main(String[] args) throws IOException {
String file = "geek-file/dos.dat";
IOUtil.printHex(file);
System.out.println();
DataInputStream dataInputStream = new DataInputStream(new FileInputStream(file));
int i = dataInputStream.readInt();
System.out.println("i = " + i);
// 10
i = dataInputStream.readInt();
System.out.println("i = " + i);
// -10
long l = dataInputStream.readLong();
System.out.println("l = " + l);
// 10
double v = dataInputStream.readDouble();
System.out.println("v = " + v);
// 10.5
String utf = dataInputStream.readUTF();
System.out.println("utf = " + utf);
// 中国
dataInputStream.close();
}
}
字节缓冲流~BufferedInputStream & BufferedOutputStream。
为 io 提供了带缓冲区的操作。一般打开文件进行定稿或读取操作时都会加上缓冲。这种流模式提高了 IO 的性能。
eg. 从应用程序中把输入放入文件相当于将一缸水倒入到另一个缸中。
FileOutputStream -> write(); 方法相当于一滴一滴地把水转移过去。
DataOutputStream -> writeXxx(); 方法会方便一些,相当于一瓢一瓢把水转移过去。
BufferedOutputStream -> write(); 方法会更方便,相当于一瓢一瓢先把水转移到一个桶中,再把一桶水转移到另一缸。
package com.geek.io;
import java.io.*;
public class IOUtil {
/**
* 进行文件拷贝,利用带缓冲的字节流。
*
* @param srcFile
* @param destFile
*/
// CopyTest02。
public static void copyFileByBuffer(File srcFile, File destFile) throws IOException {
if (!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在。");
}
if (!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件。");
}
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFile));
int c;
while ((c = bufferedInputStream.read()) != -1) {
bufferedOutputStream.write(c);
bufferedOutputStream.flush();// 刷新缓冲区。
}
bufferedOutputStream.close();
bufferedInputStream.close();
}
}
- test。
package com.geek.out;
import com.geek.io.IOUtil;
import java.io.File;
import java.io.IOException;
public class CopyTest02 {
public static void main(String[] args) {
try {
IOUtil.copyFileByBuffer(new File("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), new File("/home/geek/IdeaProjects/geek_file/geek-file/geek01.txt"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.geek.io;
import java.io.*;
public class IOUtil {
/**
* 单字节,不带缓冲进行文件拷贝。
*
* @param srcFile
* @param destFile
* @throws IOException
*/
// CopyTest03。
public static void copyFileByByte(File srcFile, File destFile) throws IOException {
if (!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在。");
}
if (!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件。");
}
FileInputStream fileInputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
int c;
while ((c = fileInputStream.read()) != -1) {
fileOutputStream.write(c);
fileOutputStream.flush();// 刷新缓冲区。
}
fileOutputStream.close();
fileInputStream.close();
}
}
- test。
package com.geek.out;
import com.geek.io.IOUtil;
import java.io.File;
import java.io.IOException;
public class CopyTest02 {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try {
IOUtil.copyFileByByte(new File("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), new File("/home/geek/IdeaProjects/geek_file/geek-file/geek02.txt"));
} catch (IOException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println((end + start) + " ms...");
}
}
字符流。
编码问题。
文本 & 文本文件。
-
Java 文本(char)是 16 位无符号整数,是字符的 unicode 编码(双字节编码)。
-
文件是 byte byte byte 的数据序列。
-
文本文件是文本(char)序列按照某种编码方案(utf-8, utf-16be, gbk)序列化为 byte 的存储结果。
-
字符流(Reader,Write)
字符的处理,一次处理一个字符。
字符的底层仍然是基本的字节序列。
字符流的基本实现~操作文本文件。
字符字节转换流~InputStreamReader & OutputSreamWriter。
- InputStreamReader。
完成 byte 流解析为 char 流。按照编码解析。
- OutputSreamWriter。
提供 char 流 ——> byte 流。按照编码处理。
- 读取。
package com.geek.stream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputStreamReaderAndOutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), "utf-8");// 默认项目编码.
// int c;
// while ((c = inputStreamReader.read()) != -1) {
// System.out.print((char) c);
// // Hello, Geek.
// }
char[] buffer = new char[8 * 1024];
int c;
// 从 inputStreamReader 中批量读取字节,放入到 buf 字节数组中,
// 从第 0 个位置开始,最多放 buf.length 个。
// 返回的是读到的字符个数。
while ((c = inputStreamReader.read(buffer, 0, buffer.length)) != -1) {
String s = new String(buffer, 0, c);
System.out.print(s);
}
}
}
- 读取 + 复制。
package com.geek.stream;
import java.io.*;
public class InputStreamReaderAndOutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), "utf-8");// 默认项目编码.
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek03.txt"), "utf-8");// 默认项目编码.
// int c;
// while ((c = inputStreamReader.read()) != -1) {
// System.out.print((char) c);
// // Hello, Geek.
// }
char[] buffer = new char[8 * 1024];
int c;
// 从 inputStreamReader 中批量读取字节,放入到 buf 字节数组中,
// 从第 0 个位置开始,最多放 buf.length 个。
// 返回的是读到的字符个数。
while ((c = inputStreamReader.read(buffer, 0, buffer.length)) != -1) {
String s = new String(buffer, 0, c);
System.out.print(s);
outputStreamWriter.write(buffer, 0, c);
outputStreamWriter.flush();
}
outputStreamWriter.close();
inputStreamReader.close();
}
}
字符流~文件读写流~FileReader & FileWriter。
package com.geek.charstream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileReaderANdFileWriterDemo {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt");
FileWriter fileWriter = new FileWriter("/home/geek/IdeaProjects/geek_file/geek-file/geek04.txt");
FileWriter fileWriter1 = new FileWriter("/home/geek/IdeaProjects/geek_file/geek-file/geek04.txt", true);
char[] buffer = new char[2056];
int c;
while ((c = fileReader.read()) != -1) {
fileWriter.write(buffer, 0, c);
fileWriter.flush();
}
fileWriter.close();
fileReader.close();
}
}
字符流过滤器~BufferedReader & BufferedWriter。
package com.geek.charstream;
import java.io.*;
public class BufferedReaderAndBufferedWriterOrPrintWriterDemo {
public static void main(String[] args) throws IOException {
// 对文件进行读写操作。
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(
new FileInputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt")
));
BufferedWriter bufferedWriter = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek5.txt")
));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);// 并不能识别换行。
bufferedWriter.write(line);
// 单独换行。
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
}
}
PrintWriter。
package com.geek.charstream;
import java.io.*;
public class BufferedReaderAndBufferedWriterOrPrintWriterDemo {
public static void main(String[] args) throws IOException {
// 对文件进行读写操作。
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(
new FileInputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt")
));
// BufferedWriter bufferedWriter = new BufferedWriter(
// new OutputStreamWriter(
// new FileOutputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek5.txt")
// ));
PrintWriter printWriter = new PrintWriter("/home/geek/IdeaProjects/geek_file/geek-file/geek6.txt.txt");
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);// 并不能识别换行。
// bufferedWriter.write(line);
// // 单独换行。
// bufferedWriter.newLine();
// bufferedWriter.flush();
printWriter.println(line);
printWriter.flush();
}
// bufferedWriter.close();
printWriter.close();
bufferedReader.close();
}
}
- 构造。
public PrintWriter(OutputStream out, boolean autoFlush) {
this(out, autoFlush, Charset.defaultCharset());
}
对象的序列化和反序列化。
-
对象的序列化,就是将 Object 转化为 byte 序列,反之叫对象的反序列化。
-
序列化流(ObjectOutputStream),是过滤流~writeObject();。
反列化流(ObjectInputStream),readObject();。
序列化接口~Serializable。
对象必须实现序列化接口,才能进行序列化,否则将出现异常。
这个接口没有任何方法,只是一个标准。
package com.geek.serialzable;
public class Student {
private String stuno;
private String stuname;
private int stuage;
public Student() {
}
public Student(String stuno, String stuname, int stuage) {
this.stuno = stuno;
this.stuname = stuname;
this.stuage = stuage;
}
public String getStuno() {
return stuno;
}
public void setStuno(String stuno) {
this.stuno = stuno;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public int getStuage() {
return stuage;
}
public void setStuage(int stuage) {
this.stuage = stuage;
}
}
package com.geek.serializable;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
* 序列化。
*/
public class ObjectSerializeDemo {
public static void main(String[] args) throws IOException {
String file = "geek-file/obj.dat";
// 对象的序列化。
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
Student student = new Student("10001", "张三", 20);
objectOutputStream.writeObject(student);
objectOutputStream.flush();
objectOutputStream.close();
// Exception in thread "main" java.io.NotSerializableException: com.geek.serializable.Student
}
}
Exception in thread “main” java.io.NotSerializableException: com.geek.serializable.Student
public class Student implements Serializable {
网络传输也需要 implements Serializable。
反序列化。
package com.geek.serializable;
import java.io.*;
/**
* 序列化 & 反序列化。
*/
public class ObjectSerializeDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// objectOutputStream();// 序列化。
objectInputStream();// 反序列化。
}
private static void objectOutputStream() throws IOException {
String file = "geek-file/obj.dat";
// 对象的序列化。
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
Student student = new Student("10001", "张三", 20);
objectOutputStream.writeObject(student);
objectOutputStream.flush();
objectOutputStream.close();
// Exception in thread "main" java.io.NotSerializableException: com.geek.serializable.Student
}
private static void objectInputStream() throws IOException, ClassNotFoundException {
String file = "geek-file/obj.dat";
// 对象的反序列化。
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
Object o = objectInputStream.readObject();
System.out.println("o = " + o);
Student student = (Student) o;
System.out.println("student = " + student);
objectInputStream.close();
}
}
transient。
adj. 短暂的;转瞬即逝的;倏忽;暂住的;过往的;临时的
n. 暂住某地的人;过往旅客;临时工
该元素不会进行 jvm 默认的序列化。
package com.geek.serializable;
import java.io.*;
/**
* 序列化 & 反序列化。
*/
public class ObjectSerializeDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// objectOutputStream();// 序列化。
objectInputStream();// 反序列化。
// 增加 transient 后不重新序列化。(修改 Class Student)。
// Exception in thread "main" java.io.InvalidClassException: com.geek.serializable.Student; local class incompatible: stream classdesc serialVersionUID = 2455853989772884997, local class serialVersionUID = -9089186181677793641
// private transient int stuage;// 该元素不会进行 jvm 默认的序列化。
// student = Student{stuno='10001', stuname='张三', stuage=0}
}
private static void objectOutputStream() throws IOException {
String file = "geek-file/obj.dat";
// 对象的序列化。
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
Student student = new Student("10001", "张三", 20);
objectOutputStream.writeObject(student);
objectOutputStream.flush();
objectOutputStream.close();
// Exception in thread "main" java.io.NotSerializableException: com.geek.serializable.Student
}
private static void objectInputStream() throws IOException, ClassNotFoundException {
String file = "geek-file/obj.dat";
// 对象的反序列化。
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
Object o = objectInputStream.readObject();
System.out.println("o = " + o);
Student student = (Student) o;
System.out.println("student = " + student);
objectInputStream.close();
}
}
也可以自己序列化。
参考 ArrayList 源码。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
transient Object[] elementData;
private int size;
private static final int MAX_ARRAY_SIZE = 2147483639;
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
private void writeObject(ObjectOutputStream s) throws IOException {
int expectedModCount = this.modCount;
s.defaultWriteObject();
s.writeInt(this.size);
for(int i = 0; i < this.size; ++i) {
s.writeObject(this.elementData[i]);
}
if (this.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
- 序列化。
package com.geek.serializable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Student implements Serializable {
private String stuno;
private String stuname;
private transient int stuage;// 该元素不会进行 jvm 默认的序列化。
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();// 把 jvm 能默认序列化的元素进行序列化操作。
s.writeInt(this.stuage);// 自己完成 stuage 的序列化。
}
public Student() {
}
public Student(String stuno, String stuname, int stuage) {
this.stuno = stuno;
this.stuname = stuname;
this.stuage = stuage;
}
public String getStuno() {
return stuno;
}
public void setStuno(String stuno) {
this.stuno = stuno;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public int getStuage() {
return stuage;
}
public void setStuage(int stuage) {
this.stuage = stuage;
}
@Override
public String toString() {
return "Student{" +
"stuno='" + stuno + '\'' +
", stuname='" + stuname + '\'' +
", stuage=" + stuage +
'}';
}
}
- 反序列化。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
s.readInt();
if (this.size > 0) {
SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, this.size);
Object[] elements = new Object[this.size];
for(int i = 0; i < this.size; ++i) {
elements[i] = s.readObject();
}
this.elementData = elements;
} else {
if (this.size != 0) {
throw new InvalidObjectException("Invalid size: " + this.size);
}
this.elementData = EMPTY_ELEMENTDATA;
}
}
package com.geek.serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Student implements Serializable {
private String stuno;
private String stuname;
private transient int stuage;// 该元素不会进行 jvm 默认的序列化。
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();// 把 jvm 能默认序列化的元素进行序列化操作。
s.writeInt(this.stuage);// 自己完成 stuage 的序列化。
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();// 把虚拟机默认能反序列化的元素进行反序列化操作。
this.stuage = s.readInt();// 自己完成 stuage 的反序列化操作。
}
public Student() {
}
public Student(String stuno, String stuname, int stuage) {
this.stuno = stuno;
this.stuname = stuname;
this.stuage = stuage;
}
public String getStuno() {
return stuno;
}
public void setStuno(String stuno) {
this.stuno = stuno;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public int getStuage() {
return stuage;
}
public void setStuage(int stuage) {
this.stuage = stuage;
}
@Override
public String toString() {
return "Student{" +
"stuno='" + stuno + '\'' +
", stuname='" + stuname + '\'' +
", stuage=" + stuage +
'}';
}
}
// student = Student{stuno=‘10001’, stuname=‘张三’, stuage=0}
// student = Student{stuno=‘10001’, stuname=‘张三’, stuage=20}
禁止某些字段序列化可提高程序效率。
ArrayList 手动对有效元素进行序列化。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
transient Object[] elementData;
private int size;
private static final int MAX_ARRAY_SIZE = 2147483639;
private void writeObject(ObjectOutputStream s) throws IOException {
int expectedModCount = this.modCount;
s.defaultWriteObject();
s.writeInt(this.size);
for(int i = 0; i < this.size; ++i) {
s.writeObject(this.elementData[i]);
}
if (this.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
s.readInt();
if (this.size > 0) {
SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, this.size);
Object[] elements = new Object[this.size];
for(int i = 0; i < this.size; ++i) {
elements[i] = s.readObject();
}
this.elementData = elements;
} else {
if (this.size != 0) {
throw new InvalidObjectException("Invalid size: " + this.size);
}
this.elementData = EMPTY_ELEMENTDATA;
}
}
序列化中子父类构造函数的问题。
package com.geek.serializable;
import java.io.*;
/**
* 序列化 & 反序列化。
*/
public class ObjectSerializeDemo02 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// oos();// 序列化。
ois();// 反序列化。
}
// 序列化。
private static void oos() throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
// new FileOutputStream("geek-file/obj1.dat"));
new FileOutputStream("geek-file/obj2.dat"));
// Foo2 foo2 = new Foo2();
Bar2 bar2 = new Bar2();
// objectOutputStream.writeObject(foo2);
objectOutputStream.writeObject(bar2);
objectOutputStream.flush();
objectOutputStream.close();
}
// 反序列化是否递归调用父类的构造函数。
// Foo 2。
// foo...
// Foo1...
// Foo2...
// foo2 = com.geek.serializable.Foo2@5056dfcb
// Bar 2。
// (Bar 1 实现序列化接口)。
// Bar...
// bar2 = com.geek.serializable.Bar2@337d0578
//
// Bar 没有显式 implements Serializable。
// 构造方法被调用。
//
// 如果 Bar 2 显式 implements Serializable。
// 其他没有。
// Bar...
// Bar1...
// bar2 = com.geek.serializable.Bar2@13a57a3b
// ==>
// 对自类对象进行反序列化操作时,
// 如果其父类没有实现序列化接口,
// 那么其父类的构造函数会被调用。
// 反序列化。
private static void ois() throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(
// new FileInputStream("geek-file/obj1.dat")
new FileInputStream("geek-file/obj2.dat")
);
// Foo2 foo2 = (Foo2) objectInputStream.readObject();
Bar2 bar2 = (Bar2) objectInputStream.readObject();
// System.out.println("foo2 = " + foo2);
System.out.println("bar2 = " + bar2);
objectInputStream.close();
}
}
// 一个类实现了序列化接口,其自类都可以进行序列化。
class Foo implements Serializable {
public Foo() {
System.out.println("foo...");
}
}
class Foo1 extends Foo {
public Foo1() {
System.out.println("Foo1...");
}
}
class Foo2 extends Foo1 {
public Foo2() {
System.out.println("Foo2...");
}
}
class Bar {
public Bar() {
System.out.println("Bar...");
}
}
class Bar1 extends Bar {
public Bar1() {
System.out.println("Bar1...");
}
}
class Bar2 extends Bar1 implements Serializable {
public Bar2() {
System.out.println("Bar2...");
}
}