java IO 输入输出流
编码问题
File 类的使用
RandomAccessFile的使用
字节流的使用
字符流的使用
对象的序列化和反序列化
1.编码问题
GBK编码,中文占用两个字节,英文占用一个字节。
UTF-8编码,中文占用三个字节,英文占用一个字节。
java是双字节编码,UTF-16be,中文占用两个字节,英文也是占用两个字节。
tips:当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要这个编码,不然会出现乱码。 文本文件就是字节序列,可以是任意编码的字节序列,如果我们在中文机器上面自动创建文本文件,那么该文件只认识ansi编码,
相关代码:
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "王文杰123";
byte[] bytes1 = s.getBytes(); // 转换成字节序列使用的是项目默认的字节编码
byte[] bytes = s.getBytes("GBK"); // 转换成字节序列使用的是项目默认的字节编码
// for (byte b : bytes) {
// //把字节转换成了int,然后以16进制显示
// System.out.print(Integer.toHexString(b & 0xff)+" ");
// }
byte[] bytes2 = s.getBytes("UTF-16BE"); // 转换成字节序列使用的是项目默认的字节编码
for (byte b : bytes2) {
//把字节转换成了int,然后以16进制显示
System.out.print(Integer.toHexString(b & 0xff)+" ");
}
System.out.println(new String(bytes2,"UTF-16BE"));
System.out.println(new String(bytes2,"GBK"));
}
2.FILE 类的使用
常用的API
java.IO.file类用于表示目录和文件
file类只用于表示文件或者目录的信息,比如名称,大小,etc. 。不能用于文件内容的访问。
相关代码:
{
public static void main(String[] args) throws IOException {
File file = new File("D:" + File.separator + "IDEA/wenjiewang");
System.out.println("判断文件是否存在:" + file.exists());
if (!file.exists()) {
file.mkdir();
} else {
file.delete(); // 删除文件或者目录
}
// 不是目录或者目录不存在返回false
System.out.println("判断是否是目录:" + file.isDirectory());
System.out.println("判断是否是文件:" + file.isFile());
file.createNewFile(); //创建文件
// 常用的File对象的API
System.out.println(file); // 打印file对象的path
System.out.println(file.getAbsolutePath()); // file 对象的目录
System.out.println(file.getName()); // 打印文件的名称
System.out.println(file.getParent()); // 获取父目录
}
}
常用操作
获取目录下的子文件
// File 类的常用操作
// 过滤 遍历
public class FileUtils {
public static void main(String[] args) {
listDirectory(new File("D:\\IDEA\\mmall\\src\\main\\java\\com\\mmall\\common"));
}
// 列出指定目录以及子目录下的所有文件
public static void listDirectory(File dir) {
if (!dir.exists() || !dir.isDirectory()) {
throw new IllegalArgumentException("目录" + dir + "不存在或不是目录!");
}
// 获取子目录 返回字符串
String[] dirList = dir.list();
for (String path : dirList) {
System.out.println(path);
}
// 获取子目录 返回File对象
File[] fileList = dir.listFiles();
for (File file : fileList) {
System.out.println(file);
// 递归遍历整个目录
if (file.isDirectory()) {
listDirectory(file);
}
}
// 遍历整个目录 然后返回.java结尾的所有文件目录
File[] list = dir.listFiles(new FilenameFilter() {
private Pattern pattern = Pattern.compile(".java");
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
});
Arrays.sort(list);
for (File path : list) {
if (path.isDirectory()) {
listDirectory(path);
}
System.out.println(path);
}
}
}
3.RandomAccessFile的使用
java提供的对文件内容的访问,既可以读文件,也可以写文件,而且,可以随机访问文件,可以访问文件的任意位置。
java 文件模型
1.1. 在硬盘上的文件是byte数组的集合,
打开文件
2.1 有两种模式"RW",“R”, 读写和只读的两种模式
RandomAccessFile raf= new RandomAccessFile(file , “RW”);
文件指针Pointer默认为0,随着你的操作,文件的指针会后移,数字变大
写方法
3.1 raf.write(int); ----> 只写一个字节。同时指针指向下个位置,准备下次写;
读方法
4.1 int b= raf.read() —> 读一个字节,然后把字节转化为整数
文件读写完以后一定要关闭
相关代码
{
public static void main(String[] args) throws IOException {
File file = new File(".//wenjie//raf.txt");
if (!file.exists()) {
file.createNewFile();
}
RandomAccessFile raf = new RandomAccessFile(file, "rw");
System.out.println("指针的位置:" + raf.getFilePointer());
raf.write('A');
System.out.println("指针的位置:" + raf.getFilePointer());
raf.write('B');
int i = 0x7fffffff;
// 用write方法每次只能写一个字节,如果把i写进去就得写四次。
raf.write(i >>> 24);
raf.write(i >>> 16);
raf.write(i >>> 8);
raf.write(i);
System.out.println("指针的位置:" + raf.getFilePointer());
raf.writeInt(i);
// 读文件,必须把指针移到最前面;
raf.seek(0);
// 一次性读取,把所有文件都读取到字节数组中
byte[] buf = new byte[(int) raf.length()];
raf.read(buf);
for (byte b : buf) {
System.out.print(Integer.toHexString(b & 0xff)+" ");
}
System.out.println(Arrays.toString(buf));
// 构造成字符串
String s = new String(buf);
System.out.println(s);
// 操作完要关闭。
raf.close();
}
}
IO流可以分为输入流,输出流。输入输出流又可以分为字节流,字符流。**
1.字节流
1.1 InputStream、OutputStream
InputStream 抽象了应用程序读取数据的方式;
OutputStream 抽象了应用程序写出数据的方式。
1.2 EOF = END 读到-1表示读到结尾
1.3 输入流的基本方法
int a = input.read();读取一个字节,无符号填充到int低八位,-1 是EOF。
in.read(byte[] bufs); 读取数据填充到字节数组bufs;
in.read(byte[] bufs,int start,int size); 读取数据到buf,从start开始读取size个长度。
1.4 输出流
out.write(int a); 写出一个byte到流,a的低八位。
out.write(byte[] bufs); 将buf字节数组写入到流。
out.write(byte[] bufs,int start,int size); 同read相同,写bufs到流从start开始写size。
4 字节流的使用
文件输入流FileInputStream
FilInputStream 具体实现了从文件上读取数据。
相关代码
{
// 读取文件内容,然后以16进制输出到控制台
// 每输出十个,然后换行
public static void inputStreamRead(String path) throws IOException {
FileInputStream fis = null;
try {
File file = new File(path);
//把文件作为流去操作;
fis = new FileInputStream(file);
int b;
int i = 1;
while ((b = fis.read()) != -1) {
if (b <= 0xf) {
//单位数前面补0
System.out.print("0");
}
System.out.printf(Integer.toHexString(b));
System.out.print(" ");
i++;
if (i % 15 == 0) {
System.out.println();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
fis.close();
}
}
public static void inputStreamByte(String path) throws IOException {
FileInputStream fis = null;
byte[] buf = new byte[20 * 1024];
try {
File file = new File(path);
//把文件作为流去操作;
fis = new FileInputStream(file);
// 从0开始读,读出来的数据放到buf数组中,返回的是读取的字节的个数
// 一次性读完说明数组足够大
int b = fis.read(buf, 0, buf.length);
int j = 0;
for (int i = 0; i < b; i++) {
System.out.print(Integer.toHexString(buf[i] & 0xFF) + " ");
if (j++ % 15 == 0) {
System.out.println();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
fis.close();
}
}
public static void inputStreamByte2(String path) throws IOException {
FileInputStream fis = null;
byte[] buf = new byte[20 * 1024];
try {
File file = new File(path);
fis = new FileInputStream(file);
int j = 0;
int b = 0;
while ((b = fis.read(buf, 0, buf.length)) != -1) {
for (int i = 0; i < b; i++) {
System.out.print(Integer.toHexString(buf[i] & 0xFF) + " ");
if (j++ % 15 == 0) {
System.out.println();
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
fis.close();
}
}
}
buf[i] & 0xFF
char 是8位,int是32位,char转到int的时候前面会自动补1,所以需要使用0xFF将前面的24位数字清空。
文件输入流FileInputStream
实现了向文件中写出byte数据的方法
{
public static void main(String[] args) throws IOException {
File file = new File("./wenjie/raf1.txt");
FileOutputStream fos = null;
try {
// 如果文件不存在就会自动创建,存在就会删除后创建
// 第二个参数就会控制在后面追加内容,不会删除。
fos = new FileOutputStream(file);
String a = "这是一个测试用的字符串!";
byte[] bytes = a.getBytes();
fos.write(bytes);
int i = 11;
fos.write(i >>> 24);
fos.write(i >>> 16);
fos.write(i >>> 8);
fos.write(i);
fos.write(String.valueOf(i).getBytes());
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fos.close();
}
}
}
DataoutputStream / DataInputStream
是对流的扩展,可以更加方便的读取int long 字符等类型的数据
DataOutputStream —>
public static void main(String[] args) throws IOException {
FileOutputStream fos = null;
DataOutputStream dos = null;
FileInputStream fis = null;
DataInputStream dis = null;
try {
File file = new File("./wenjie/raf.txt");
fos = new FileOutputStream(file);
dos = new DataOutputStream(fos);
fis = new FileInputStream(file);
dis = new DataInputStream(fis);
int a = 10;
dos.writeInt(a);
dos.writeUTF("学习!");
// 输出10,使用readInt可以读取写入的数据
System.out.println(dis.readInt());
} catch (IOException e) {
e.printStackTrace();
} finally {
fos.close();
dos.close();
}
}
字节缓冲流
BufferedInputStream BufferedOutputStream
这两个流类为IO提供了带缓冲区的操作,一般打开文件进行写入或者读取操作时,都会加上缓冲,这种流模式提高了io的性能。更加方便的进行写入读取操作。写入到缓冲区,再进行写入,提高了性能。
{
/**
* 使用带缓冲的字节流进行复制操作。
*/
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("./wenjie/raf.txt")));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("./wenjie/raf1.txt")));
int buf;
while ((buf = bis.read()) != -1){
bos.write(buf);
// 刷新缓冲区
bos.flush();
}
bis.close();
bos.close();
}
}