目录
文件的编码
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "慕课ABC";
byte[] bytes1 = s.getBytes(); //把字符串转换成字符数组,转换成的字节序列用的是项目默认的编码GBK
for(byte b : bytes1){
//把字节(转换成了int)以16进制的方式显示
//toHexString这个函数是把字节(转换成了Int)以16进制的方式显示
System.out.println(Integer.toHexString(b & 0xff)+""); // & 0xff是为了把前面的24个0去掉只留下后八位
}
byte[] bytes2=s.getBytes("gbk");//也可以转换成指定的编码
for(byte b : bytes2){
//把字节(转换成了int)以16进制的方式显示
//toHexString这个函数是把字节(转换成了Int)以16进制的方式显示
System.out.println(Integer.toHexString(b & 0xff)+""); // & 0xff是为了把前面的24个0去掉只留下后八位
}
}
gbk编码: 中文占用两个字节,英文占用一个字节
utf-8编码:中文占用三个字节,英文占用一个字节
java是双字节编码,是utf-16be编码
utf-16be编码:中文占用两个字节,英文占用两个字节
当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式,否则会出现乱码
String str1=new String(bytes2);//这时会使用项目默认的编码来转换,可能出现乱码
要使用字节序列的编码来进行转换
String str2=new String(bytes2,"utf-16be");
文本文件就是字节序列,可以是任意编码的字节序列
如果我们在中文机器上直接创建文本文件,那么该文件只认识ANSI编码(例如直接在电脑中创建文本文件)
中文机器上创建的文本文件只能识别ansi编码
File类的使用
Java.IO.File类表示文件或目录,只用于表示文件或目录得信息,不能用于文件的访问。
常用的API
1.创建File对象
File file=new File(String path);注意:File.seperater();获取系统分隔符,如:”\“.
2.boolean file.exists();是否存在.
3.file.mkdir();或者file.mkdirs();创建目录或多级目录。
4.file.isDirectory()或者file.isFile()判断是否是目录或者是否是文件。
5.file.delete();删除文件或目录。
6.file.createNewFile();创建新文件。
7.file.getName()获取文件名称或目录绝对路径。
8.file.getAbsolutePath()获取绝对路径。
9.file.getParent();获取父级绝对路径。
10.file.getSize();获取文件大小。
11.file.getFormat();获取文件格式名
遍历目录
//常用操作:过滤,目录....
public class FileUtils {
/**
* 列出指定目录下的所有文件
*
* @param dir
* @throws IOException
*/
public static void listDirectory(File dir) throws IOException {
//判断文件或目录是否存在
if (!dir.exists()) {
throw new IllegalArgumentException("目录:" + dir + "不存在。"); //抛出异常
}
//判断File类的对象是否是目录
if (!dir.isDirectory()) {
throw new IllegalArgumentException(dir + "不是目录。"); //抛出异常
}
//返回的是字符串数组,列出当前目录下的所有子目录和文件,不包含子目录下的内容
String[] filenames = dir.list();
//将filenames数组中的值,循环赋值给string,直到filenames为空时,结束循环
for (String s : filenames) {
System.out.println(s);
}
}
}
如果要遍历目录下的内容就需要构造成File对象做递归操作,File提供了直接返回File对象的API:
File[] files = dir.listFiles(); //返回的是直接子目录(文件)的抽象
递归,遍历出该目录下所有文件信息,包括子目录下的文件
for(File f :files){
if(f.isDirectory()){
//递归遍历该目录下的子目录的信息
listDirectory(dir);
}else{
System.out.println(dir);
}
}
RandomAccessFile
RandomAccessFile:java提供的对文件内容的访问,既可以读文件,也可以写文件。支持随机访问文件,可以访问文件的任意位置。
文件模型
在硬盘上的文件时 byte byte byte存储的,是数据的集合
打开方式
1.rw:读写
2.r:只读
方法
raf.getFilePointer()获取当前指针位置 raf.length()获取文件长度 raf.seek()把指针指定到某一位置
写
raf.write(int) ----> 只写一个字节 (后8位) 同时指针指向下一个位置 准备再次写入
读
int b=raf.read(); 读一个字节
文件读写完成以后一定要关闭,否则会产生未知错误
IO流
IO即Input/Output,输入和输出。数据输入到计算机内存的过程叫输入;反正输出到外部设备(数据库、主机、文件)的过程叫输出。
数据传输的过程像水流。因此被称为IO流。
IO流在Java中被分为输入流和输出流,而根据数据的处理方式又分为字节流和字符流。
4大抽象类基类:
InputStream/Reader:所有的输入流的基类,前者是字节输入流,后者是字符输入流
OutputStream/Writer:所有输出流的基类,前者是字节输出流,后者是字符输出流
字节流
字节流主要是操作byte类型数据,以byte数组为准,主要操作类时字节输入流InputStream、字节输出流OutputStream
InputStream(字节输入流)
InputStream:从文件中读取数据到内存中,java.io.InputStream
抽象类是所有字节输入流的父类。
常用方法
1.in.read():返回输入流中下一个字节的数据
2.in.read(byte[] b):从输入流中读取一些字节存储到数组b中。如果数组b的长度为零,则不读取。如果没有可用字节读取,返回-1。如果有可用字节读取,则最多读取的字节数最多等于b.length
3.in.read(byte[] buf,int start,int size):在read(byte b[ ])
方法的基础上增加了 off
参数(偏移量)和 len
参数(要读取的最大字节数)
4.skip(long n):忽略输入流中的 n 个字节 ,返回实际忽略的字节数
5.available():返回输入流中可以读取的字节数
6.close():关闭输入流释放相关的系统资源
FileInputStream
FileInputStream是一个比较常用的字节输入流对象,可直接指定文件路径,可以直接读取单字节数据,也可以读取至字节数组中。
示例:
try (InputStream fis = new FileInputStream("input.txt")) {
System.out.println("Number of remaining bytes:"
+ fis.available());
int content;
long skip = fis.skip(2);
System.out.println("The actual number of bytes skipped:" + skip);
System.out.print("The content read from file:");
while ((content = fis.read()) != -1) {
System.out.print((char) content);
}
} catch (IOException e) {
e.printStackTrace();
}
文件内容:
结果输出:
Number of remaining bytes:11
The actual number of bytes skipped:2
The content read from file:JavaGuide
般我们是不会直接单独使用 FileInputStream
,通常会配合 BufferedInputStream
// 新建一个 BufferedInputStream 对象
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("input.txt"));
// 读取文件的内容并复制到 String 对象中
String result = new String(bufferedInputStream.readAllBytes());
System.out.println(result);
OutputStream(字节输出流)
用于将数据(字节信息)写入到文件中,java.io.OutputStream
抽象类是所有字节输出流的父类
常用方法
writer(int b):将特定字节写入输出流
writer(byte b[ ]):将数组b
写入到输出流
writer(byte b[ ],int off,int len):在write(byte b[ ])
方法的基础上增加了 off
参数(偏移量)和 len
参数(要读取的最大字节数)
flush():刷新此输出流并强制写出所有缓冲的输出字节
close():关闭输出流释放相关的系统资源
FileOutputStream
是最常用的字节输出流对象,可直接指定文件路径,可以直接输出单字节数据,也可以输出指定的字节数组
示例:
try (FileOutputStream output = new FileOutputStream("output.txt")) {
byte[] array = "JavaGuide".getBytes();
output.write(array);
} catch (IOException e) {
e.printStackTrace();
}
结果:
类似于 FileInputStream
,FileOutputStream
通常也会配合 BufferedOutputStream
(字节缓冲输出流)来使用。
FileOutputStream fileOutputStream = new FileOutputStream("output.txt");
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
字符流
字符流:就是在字节流的基础上,加上编码,形成的数据流
意义:因为字节流在操作字符时,可能会有中文导致的乱码,所以由字节流引申出了字符流。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好
Reader(字符输入流)
Reader用于从源头(通常是文件)读取数据(字符信息)到内存中,java.io.Reader
抽象类是所有字符输入流的父类
常用方法
1.in.read():从输入流中读取一个字符
2.in.read(char[] b):从输入流中读取一些字符,并将它们存储到字符数组 b
中,等价于 read(b, 0, b.length)
3.in.read(char[] buf,int off,int len):在read(char[] b)
方法的基础上增加了 off
参数(偏移量)和 len
参数(要读取的最大字符数)
4.skip(long n):忽略输入流中的 n 个字符 ,返回实际忽略的字符数
5.close():关闭输入流并释放相关的系统资源
示例
// 1.使用File类找到一个文件
File f = new File("f:\\test.txt");
// 2.实例化输入流对象
Reader input = new FileReader(f);
// 3.读操作
char[] c = new char[1024];
int len = input.read(c);
// 4.关闭流
input.close();
System.out.println("文件内容:" + new String(c,0,len));
InputStreamReader
是字节流转换为字符流的桥梁,其子类 FileReader
是基于该基础上的封装,可以直接操作字符文件。
// 字节流转换为字符流的桥梁
public class InputStreamReader extends Reader {
}
// 用于读取字符文件
public class FileReader extends InputStreamReader {
}
FileReader
try (FileReader fileReader = new FileReader("input.txt");) {
int content;
long skip = fileReader.skip(3);
System.out.println("The actual number of bytes skipped:" + skip);
System.out.print("The content read from file:");
while ((content = fileReader.read()) != -1) {
System.out.print((char) content);
}
} catch (IOException e) {
e.printStackTrace();
}
文件内容:
输出:
The actual number of bytes skipped:3
The content read from file:我是Guide。
Writer(字符输出流)
常用方法
writer();
writer(char[ ]);
writer(char[ ],offset,len);
writer(string);
flush()刷新缓冲区
close()方法默认调用了flush()方法,但是flush()方法只刷新缓冲区,而close()还会关闭IO流
示例
//1.使用File类找到一个文件
File f = new File("f:\\test.txt");
//2.实例化输出流对象
Writer out = new FileWriter(f);
//3.写操作
String str = "Hello World!!";
out.write(str);
//4.关闭流
out.close();
OutputStreamWriter
是字符流转换为字节流的桥梁,其子类 FileWriter
是基于该基础上的封装,可以直接将字符写入到文件
// 字符流转换为字节流的桥梁
public class OutputStreamWriter extends Writer {
}
// 用于写入字符到文件
public class FileWriter extends OutputStreamWriter {
}
FileWriter
try (Writer output = new FileWriter("output.txt")) {
output.write("你好,我是Guide。");
} catch (IOException e) {
e.printStackTrace();
}
输出结果:
字符流与字节流的区别
1.字节流在操作的时候本身不用缓存区的,是与文件直接对接的;而字符流操作时需要缓冲区。
2.使用字节流时,即使流没有关闭,最终也可以输出到文件;
3.使用字符流时,所有的内容保存在缓冲区,流关闭时 会强制性的将缓冲区内容写到文件中,如果没有关闭流,文件中就不会有内容输出。
字节缓冲流
IO 操作是很消耗性能的,缓冲流将数据加载至缓冲区,一次性读取/写入多个字节,从而避免频繁的 IO 操作,提高流的传输效率。
字节缓冲流这里采用了装饰器模式来增强 InputStream
和OutputStream
子类对象的功能。
字符缓冲流
BufferedReader
(字符缓冲输入流)和 BufferedWriter
(字符缓冲输出流)类似于 BufferedInputStream
(字节缓冲输入流)和BufferedOutputStream
(字节缓冲输入流),内部都维护了一个字节数组作为缓冲区。不过,前者主要是用来操作字符信息。