一. File
File是Java.io.包下的类,File类的对象用于代表当前操作系统的文件/文件夹
File类只能对文件本身进行操作,不能读写文件里面存储的数据。
1. 创建对象
构造器 | 说明 |
public File(String pathname) | 根据文件路径创建文件对象 |
public File(String parent, String child) | 根据父路径和子路径名字创建文件对象--使用较少 |
public File(File parent, String child) | 根据父路径对应文件对象和子路径名字创建文件对象--使用较少 |
public static void main(String[] args) {
//public File(String pathname) 根据文件路径创建文件对象
//路径分隔符
File file = new File("D:\\桌面\\文档\\123.txt");
File file1 = new File("D:/桌面/文档/123.txt");
File file2 = new File("D:" + File.separator + "桌面" + File.separator + "文档" + File.separator + "123.txt");
//文件夹
File file3 = new File("D:/桌面/文档");
//可以指向一个不存在的文件路径
File file4 = new File("D:/桌面/11111.txt");
//绝对路径:带盘符的路径 D:\JavaCode\file-io-app\src\112233.txt
File file5 = new File("D:\\JavaCode\\file-io\\src\\112233.txt");
//相对路径:不带盘符,默认是直接去工程目录下寻找 file-io-app\src\112233.txt
File file6 = new File("file-io\\src\\112233.txt");
}
2. 常用方法
常用方法名 | 说明 |
public boolean exists() | 判断当前文件对象对应的文件路径是否存在,是则返回true |
public boolean isFile() | 判断当前文件对象指代的是否是文件,是则返回true |
public boolean isDirectory() | 判断当前文件对象指代的是否是文件夹,是则返回true |
public String getName() | 获取文件名称,包括后缀名 |
public long length() | 获取文件的大小,返回字节数 |
public long lastModified() | 获取文件的最后修改时间,返回时间毫秒值 |
public String getPath() | 获取创建对象时使用的路径 |
public String getAbsolutePath() | 获取绝对路径 |
public boolean renameTo(File dest) | 用于重命名文件或移动文件到新的位置,如果文件或目录被成功重命名或移动,则返回 true ;否则,返回 false |
public static void main(String[] args) {
File file = new File("D:\\桌面\\文档\\123.txt");
//public boolean exists() 判断当前文件对象对应的文件路径是否存在,是则返回true
System.out.println(file.exists());//true
//public boolean isFile() 判断当前文件对象指代的是否是文件,是则返回true
System.out.println(file.isFile());//true
File file3 = new File("D:\\QQ");
System.out.println(file3.isFile());//false
//public boolean isDirectory() 判断当前文件对象指代的是否是文件夹,是则返回true
System.out.println(file3.isDirectory());//true
//public String getName() 获取文件名称,包括后缀名
System.out.println(file.getName());//123.txt
//public long length() 获取文件的大小,返回字节数
System.out.println(file.length());//123.txt
//public lastModified() 获取文件的最后修改时间
long time = file.lastModified();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(time));//
//public String getPath() 获取创建对象时使用的路径
//绝对路径:带盘符的路径 D:\JavaCode\file-io-app\src\112233.txt
File file5 = new File("D:\\JavaCode\\file-io\\src\\112233.txt");
//相对路径:不带盘符,默认是直接去工程目录下寻找 file-io-app\src\112233.txt
File file6 = new File("file-io\\src\\112233.txt");
System.out.println(file5.getPath());//D:\JavaCode\file-io\src\112233.txt
System.out.println(file6.getPath());//file-io\src\112233.txt
//public String getAbsolutePath() 获取绝对路径
System.out.println(file5.getAbsolutePath());//D:\JavaCode\file-io\src\112233.txt
System.out.println(file6.getAbsolutePath());//D:\JavaCode\file-io\src\112233.txt
//public boolean renameTo(File dest) 用于重命名文件或移动文件到新的位置
File oldFile = new File("D:\\桌面\\文档\\123.txt");
File newFile = new File("D:\\桌面\\文档\\1234.txt");
if (oldFile.renameTo(newFile)) {
System.out.println("文件重命名成功!");//文件重命名成功!
} else {
System.out.println("文件重命名失败!");
}
}
创建文件常用方法 | 说明 |
public boolean createNewFile() | 创建一个新文件(文件内容为空),成功返回true |
public boolean mkdir() | 创建文件夹,只能创建一级文件夹 |
public boolean mkdirs() | 创建文件夹,可以创建多级文件夹 |
public boolean delete() | 删除文件、或空文件,不能删除非空文件夹,删除后不进回收站 |
public static void main(String[] args) throws IOException {
//创建一个不存在的文件对象
File file = new File("D:\\桌面\\文档\\456.txt");
//public boolean createNewFile() 创建一个新文件(文件内容为空),成功返回true
System.out.println(file.createNewFile());//throws IOException true
System.out.println(file.createNewFile());//再次创建则会失败(文件已存在) false
//public boolean mkdir() 创建文件夹,只能创建一级文件夹
File file1 = new File("D:\\桌面\\文档\\aaa");
System.out.println(file1.mkdir());//true
//public boolean mkdirs() 创建文件夹,可以创建多级文件夹
File file2 = new File("D:\\桌面\\文档\\123\\456\\798");
System.out.println(file2.mkdirs());//true
//public boolean delete() 删除文件、或空文件,不能删除非空文件夹
System.out.println(file1.delete());//true
File file3 = new File("D:\\桌面\\文档\\123");
System.out.println(file3.delete());//false
}
遍历文件夹的方法 | 说明 |
public String[] list() | 获取当前目录下所有的“一级文件名称”到一个字符串数组中 |
public File[] listFile() | 获取当前目录下所有的“一级文件对象”到一个对象数组中 |
public static void main(String[] args) {
File file = new File("D:\\桌面\\文档\\123");
File file0 = new File("D:\\桌面\\文档\\123\\456");
File file1 = new File("D:\\桌面\\文档\\123\\234");
File file2 = new File("D:\\桌面\\文档\\123\\345");
file0.mkdir();
file1.mkdir();
file2.mkdir();
//public String[] list() 获取当前目录下所有的“一级文件名称”到一个字符串数组中
String[] list = file.list();
for(String s : list){
System.out.println(s); //234 345 456
}
//public File[] listFile() 获取当前目录下所有的“一级文件对象”到一个对象数组中
File[] files = file.listFiles();
for(File f : files){
System.out.println(f.getName()); //234 345 456
}
}
3. 使用public File[] listFile()的注意事项
① 当主调是文件,或者路径不存在时,返回null
② 当主调是空文件夹,返回一个长度为0的数组
③ 当主调是有内容的文件夹时,将里面所有的一级文件和文件夹的路径放在File数组中
④ 当主调文件夹,且存在隐藏文件时,将里面所有的一级文件和文件夹的路径放在File数组中,包括隐藏文件
⑤ 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null
4. 方法递归
(1) 方法递归是一种算法,在程序设计语言中广泛使用;方法调用自身的形式称为方法递归。
(2) 递归的形式:
① 直接递归:方法自己调用自己
② 间接递归:方法调用其他方法,其他方法有回调方法自己
public class Test_fangfaDiGui {
public static void main(String[] args) {
//方法递归
//计算阶乘
System.out.println(fangfaDiGui(5));
}
//方法递归
public static int fangfaDiGui(int n) {
//结束点
if (n == 1) {
return 1;
}else{
return fangfaDiGui(n - 1) * n;
}
}
}
5. 递归 文件搜索
public class Test_fangfaDiGuiQQ {
public static void main(String[] args) throws IOException {
//递归 文件搜索
//例如找到D盘中的QQ.exe文件 输出其绝对路径
fangfaDiGuiQQ(new File("D:\\"), "QQ.exe");//D:\QQ\QQ.exe
}
public static void fangfaDiGuiQQ(File file, String filename) throws IOException {
if (file == null || file.exists() == false) {
return;
}
//获取当前目录的所有一级目录对象
File[] files = file.listFiles();
if (files == null || files.length == 0) {
return;
}
for (File f : files) {
//如果是文件
if(f.isFile()){
if (f.getName().equals(filename)) {
System.out.println(f.getAbsolutePath());
//启动QQ
Runtime rt = Runtime.getRuntime();
rt.exec(f.getAbsolutePath());
}
}
//如果是文件夹
if (f.isDirectory()) {
//递归
fangfaDiGuiQQ(f, filename);
}
}
}
}
6. 递归 删除非空文件夹
public class Test_3 {
public static void main(String[] args) {
//删除非空文件夹
File file = new File("D:\\桌面\\文档\\123");
deleteDir(file);
}
public static void deleteDir(File dir) {
if(dir == null || !dir.exists() || !dir.isDirectory()) {
return;
}
//是文件 直接删除
if(dir.isFile()) {
dir.delete();
return;
}
//文件夹 获取全部一级文件对象
if(dir.isDirectory()) {
File[] files = dir.listFiles();
if (files == null){
return;
}
if(files.length == 0) {
dir.delete();
return;
}
for(File file : files) {
if(file.isFile()) {
file.delete();
}
if(file.isDirectory()) {
deleteDir(file);
}
}
}
//最后将自己删除
dir.delete();
}
}
7. 字符集
(1) ASCII字符集:美国信息交换标准代码,包括了英文、符号等。
(2) 标准ASCII使用1个字节存储一个字符,首尾是0,总共可表示128个字符。
(3) GBK(汉字内码扩展规范,国标):汉字编码字符集,包含了2万多个汉字等字符,GBK中一个中文字符编码成两个字节的形式存储。兼容了ASCII字符集;GBK规定:汉字的第一个字节的第一位必须是1。
(4) Unicode字符集(统一码,也叫万国码):是国际组织制定的,可以容纳世界上所有文字、符号的字符集。
UTF-8是Unicode字符集的一种编码方案,采取可变长编码方案,共分为四个长度区:1个字节,2个字节,3个字节,4个字节。英文字符、数字等只占1个字节(兼容ASCII编码),汉字字符占用3个字节。
技术人员在开发时都应该使用UTF-8编码!字符编码时使用的字符集和解码时使用的字符集必须一致,否则后出现乱码;英文、数字一般不会乱码,因为很多字符集都兼容了ASCII编码
8. Java代码完成对字符的编码、解码
(1) 编码:把字符按照指定字符集编码成字节;
String提供了一些编码方法 | 说明 |
byte[] getBytes() | 使用平台默认字符集将该String编码成为一系列字节,将结果存储到新的字节数组中 |
byte[] getBytes(String charsetName) | 使用指定的字符集将该String编码成为一系列字节,将结果存储到新的字节数组中 |
(2) 解码:把字节按照指定字符集解码成字符。
String提供了一些解码方法 | 说明 |
String(byte[] bytes) | 使用平台默认字符集解码指定的字节数组,返回String |
String(byte[] bytes, String charsetName) | 通过指定字符集解码指定的字节数组,返回String |
public static void main(String[] args) throws UnsupportedEncodingException {
//编码
String data = "卡莎A你";
//byte[] getBytes() 使用平台默认字符集将该String编码成为一系列字节,将结果存储到新的字节数组中
byte[] b = data.getBytes();//默认UTF-8
System.out.println(Arrays.toString(b));//[-27, -115, -95, -24, -114, -114, 65, -28, -67, -96]
//byte[] getBytes(String charsetName) 使用指定的字符集将该String编码成为一系列字节,将结果存储到新的字节数组中
byte[] b2 = data.getBytes("GBK");//throws UnsupportedEncodingException 担心字符集写错异常
System.out.println(Arrays.toString(b2));//[-65, -88, -55, -81, 65, -60, -29]
//解码
//String(byte[] bytes) 使用平台默认字符集解码指定的字节数组,返回String
String s = new String(b);//默认UTF-8
System.out.println(s);//卡莎A你
String s1 = new String(b2);
System.out.println(s1);//��ɯA�� 乱码 因为b2是GBK
//String(byte[] bytes, String charsetName) 通过指定字符集解码指定的字节数组,返回String
String s2 = new String(b2, "GBK");
System.out.println(s2);//卡莎A你
}
二. IO流
IO流用读写数据的(可以读写文件或网络中的数据); I:指Input,称为输入流,负责把数据读到内存中;O:指Output,称为输出流,负责写数据出去。
1. 字节输入流 InputStream
(1) 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流。
(2) FileInputStream://流使用完之后,必须关闭释放系统资源
fis.close();
构造器 | 说明 |
public FileInputStream(File file) | 创建字节流管道与源文件接通 |
public FileInputStream(String pathname) | 创建字节流管道与源文件接通 |
方法名称 | 说明 |
public int read() | 每次读取一个字节返回,如发现没有数据可读则返回-1;读取性能较差,并且读取汉字会出现乱码。 |
public int read(byte[] buffer) | 每次用一个字节数组读取数据,返回字节数组读取了多少个字节,如发现没有数据可读则返回-1;读取性能提升,但读取汉字还有可能会出现乱码 |
(3) 解决读取乱码问题
方法一:public int read(byte[] buffer) 使用字节流读取中文,定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。
方法二:Java官方为InputStream提供了 public byte[] readAllBytes() throws IOException:直接将当前字节流对应的文件对象的字节数据装到一个字节数组返回。
如果文件过大,创建字节流数组也会过大,可能引起内存溢出异常--读写文本更适合用字符流;字节流适合做数据的迁移(如文件复制)
public static void main(String[] args) throws IOException {
//public FileInputStream(File file) 创建字节流管道与源文件接通
//public FileInputStream(String pathname) 创建字节流管道与源文件接通
/*File file = new File("D:\\桌面\\文档\\123.txt");
FileInputStream fis = new FileInputStream(file);//throws FileNotFoundException 担心文件路径不正确*/
//内容为1234
FileInputStream fis = new FileInputStream(("D:\\桌面\\文档\\1234.txt"));//throws FileNotFoundException 担心文件路径不正确
//public int read() 每次读取一个字节返回,如发现没有数据可读则返回-1 //读取的性能很差 读取中文输出会乱码!无法避免
int i;//记录每次读取的字节
while ((i = fis.read()) != -1) {
System.out.print((char) i);//1234
}
System.out.println("--------------------");
//public int read(byte[] buffer) 每次用多个字节读取数据,返回字节数组读取了多少个字节,如发现没有数据可读则返回-1
//也无法避免汉字读取乱码的问题 new byte[2]会截乱数组
FileInputStream fis1 = new FileInputStream(("D:\\桌面\\文档\\456.txt"));
byte[] buffer = new byte[2];// 每次读取1字节
int len;//记录每次读取多少字节
while ((len = fis1.read(buffer)) != -1) {
//读取多少 倒出多少 0, len
System.out.print(new String(buffer, 0, len));//456
}
System.out.println("--------------------");
//解决乱码
// 1. 使用字节流读取中文,定义一个与文件一样大的字节数组,一次性读取完文件的全部字节 --读相对来说文件较小的文件
File file = new File("D:\\桌面\\文档\\a卡莎.txt");//内容a卡莎a卡莎a卡莎a卡莎a卡莎a卡莎
FileInputStream fis2 = new FileInputStream(file);
byte[] buffer1 = new byte[(int)file.length()];
int len1;//记录每次读取多少字节
while ((len1 = fis2.read(buffer1)) != -1) {
//读取多少 倒出多少 0, len
System.out.print(new String(buffer1, 0, len1));//a卡莎a卡莎a卡莎a卡莎a卡莎a卡莎D
}
System.out.println("--------------------");
//2.Java官方为InputStream提供了 public byte[] readAllBytes() throws IOException:直接将当前字节流对应的文件对象的字节数据装到一个字节数组返回
File file1 = new File("D:\\桌面\\文档\\a卡莎.txt");//内容a卡莎a卡莎a卡莎a卡莎a卡莎a卡莎
FileInputStream fis3 = new FileInputStream(file1);
byte[] buffer2 = fis3.readAllBytes();
System.out.println(new String(buffer2));//a卡莎a卡莎a卡莎a卡莎a卡莎a卡莎
//流使用完之后,必须关闭释放系统资源
fis.close();
}
2. 字节输出流 OutputStream
(1) 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流。
(2) FileOutputStream:文件字节输出流
构造器 | 说明 |
public FileOutputStream(File file) | 创建字节输出流管道与源文件对象接通 |
public FileOutputStream(String filepath) | 创建字节输出流管道与源文件路径接通 |
public FileOutputStream(File file, boolean append) | 创建字节输出流管道与源文件对象接通,可追加数据 |
public FileOutputStream(String filepath, boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
方法名称 | 说明 |
public void write(int a ) | 写一个字节出去 |
public void write(byte[] buffer ) | 写一个字节数组出去 |
public void write(byte[] buffer, int pos, int len ) | 写一个字节数组的一部分数据出去 |
public void close() throws IOException | 关闭流 |
//换行符
outputStream1.write("\r\n".getBytes());
public static void main(String[] args) throws Exception {
//public FileOutputStream(String filepath) 创建字节输出流管道与源文件路径接通
//会清空之前的数据
OutputStream outputStream = new FileOutputStream("D:\\桌面\\文档\\11122.txt");//文件自动生成
outputStream.write(97);//97是一个字节 代表a ASCII码
outputStream.write('u');//
outputStream.write('卡');// UTF-8 汉字默认占3个字节 而这里只能存一个字节 乱码
//使用字节流数组输出汉字
byte[] bytes = "卡莎墨菲特".getBytes();
outputStream.write(bytes);
outputStream.write(bytes, 0, bytes.length);
//执行多次 文件内容 aua卡莎墨菲特
outputStream.close();
//追加管道 不会清空之前的数据 拼接到后面
//public FileOutputStream(String filepath, boolean append) 创建字节输出流管道与源文件路径接通,可追加数据
OutputStream outputStream1 = new FileOutputStream("D:\\桌面\\文档\\1112233.txt" , true);//文件自动生成
outputStream1.write(97);
outputStream1.write('u');
outputStream1.write('卡');
//使用字节流数组输出汉字
byte[] bytes1 = "卡莎墨菲特".getBytes();
outputStream1.write(bytes1);
outputStream1.write(bytes1, 0, bytes.length);
//执行多次 文件内容 aua卡莎墨菲特aua卡莎墨菲特aua卡莎墨菲特卡莎墨菲特
//换行符
outputStream1.write("\r\n".getBytes());
outputStream1.close();
}
//文件复制:任何文件的底层都是字节,字节流做复制文件是一字不漏的转移全部字节,只要文件格式一致就没问题!
public static void main(String[] args) throws Exception {
//复制文件
// 创建字节输入流 源文件 D:\桌面\文档\1112233.txt
InputStream is = new FileInputStream("D:\\桌面\\文档\\1112233.txt");
//创建字节输出流 复制到 D:\桌面\文档\111223344.txt
OutputStream os = new FileOutputStream("D:\\桌面\\文档\\111223344.txt");
//创建字节数组 转移字节数据
byte[] b = new byte[1024];
//从字节输入流中读取数据,写到字节输出流 读多少写多少
int len = 0;
while ((len = is.read(b)) != -1) {
os.write(b, 0, len);
}
is.close();
os.close();
}
3. 释放资源的方式
创建流与关闭流中间的代码可能会出现异常,这样就执行不到.close(),就不会释放流,从而占用系统资源;使用以下方法可释放资源
(1) try-catch-finally
① 格式:try{
代码
}catch(IOException e){
e.printStskTrace();
}finally{
//代码
}
② finally代码区:无论try中的程序是否出现异常,最后都会执行finally代码区,除非jvm终止
③ 千万不要在finally里面return数据,会导致方法最终返回的结果不准确。
④ 一般用于在程序执行完成后进行资源释放的操作
public static void main(String[] args) {
//复制文件
InputStream is = null;
OutputStream os = null;
try{
// 创建字节输入流 源文件 D:\桌面\文档\1112233.txt
is = new FileInputStream("D:\\桌面\\文档\\1112233.txt");
//创建字节输出流 复制到 D:\桌面\文档\111223344.txt
os = new FileOutputStream("D:\\桌面\\文档\\111223344.txt");
//创建字节数组 转移字节数据
byte[] b = new byte[1024];
//从字节输入流中读取数据,写到字节输出流 读多少写多少
int len = 0;
while ((len = is.read(b)) != -1) {
os.write(b, 0, len);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//如果创建流之前就出现异常
if (is != null ) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os != null ) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
(2) try-with-resource
JDK7开始提供try-with-resource:更加简洁的释放资源
① 格式:try(定义资源1;定义资源2;.....){
//可能出现异常的代码
}catch(异常类名变量名){
//异常处理
}
② 该资源使用完毕后,会自动调用其close()方法,完成对资源的释放
③ try(定义资源1;定义资源2;.....) 中只能放资源对象;资源一般指的是最终都会实现AutoColseable接口
public static void main(String[] args) {
//复制文件
//try-with-resource
try(
// 创建字节输入流 源文件 D:\桌面\文档\1112233.txt
InputStream is = new FileInputStream("D:\\桌面\\文档\\1112233.txt");
//创建字节输出流 复制到 D:\桌面\文档\111223344.txt
OutputStream os = new FileOutputStream("D:\\桌面\\文档\\111223344.txt");
){
//创建字节数组 转移字节数据
byte[] b = new byte[1024];
//从字节输入流中读取数据,写到字节输出流 读多少写多少
int len = 0;
while ((len = is.read(b)) != -1) {
os.write(b, 0, len);
}
}catch (Exception e){
e.printStackTrace();
}
}
4. 字符输入流 Reader
字节流:适合复制文件等,不适合读写文本文件(容易乱码),读写文本文件字符流更适合
(1) 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流。
(2) FileReader
构造器 | 说明 |
public FileReader(File file) | 创建字符输入流管道与源文件接通 |
public FileReader(String pathname) | 创建字符输入流管道与源文件接通 |
方法名称 | 说明 |
public int read() | 每次读取一个字符返回,如果发现没有可读数据就返回-1 |
public int read(char[] buffer) | 每次用一个字符数组去读取数据,返回字符数组读取了多少个字符,如果发现没有可读数据就返回-1 |
public static void main(String[] args) {
//public FileReader(String pathname) 创建字符输入流管道与源文件接通
try(
Reader reader = new FileReader("D:\\桌面\\文档\\1234.txt");//内容为1234
Reader reader1 = new FileReader("D:\\桌面\\文档\\11122.txt");//aua卡莎墨菲特卡莎墨菲特
) {
//public int read() 每次读取一个字符返回,如果发现没有可读数据就返回-1
// 性能较差
int c;//每次读取一个字符编号
while ((c = reader.read()) != -1) {
System.out.print((char) c);//1234
}
//public int read(char[] buffer) 每次用一个字符数组去读取数据,返回字符数组读取了多少个字符,如果发现没有可读数据就返回-1
// 性能较好
char[] buf = new char[4];
int len;//记记录每次读取多少字符
while ((len = reader1.read(buf)) != -1) {
System.out.print(new String(buf, 0, len));//aua卡莎墨菲特卡莎墨菲特
}
} catch (Exception e) {
e.printStackTrace();
}
}
5. 字符输出流 Writer
(1 )字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流。
(2) FileWriter
构造器 | 说明 |
public FileWriter(File file) | 创建字节输出流管道与源文件接通 |
public FileWriter(String filepath) | 创建字节输出流管道与源文件接通 |
public FileWriter(File file, boolean append) | 创建字节输出流管道与源文件接通,可追加数据 |
public FileWriter(String filepath, boolean append) | 创建字节输出流管道与源文件接通,可追加数据 |
方法名称 | 说明 |
void write(int c) | 写一个字符 |
void write(String s) | 写一个字符串 |
void write(String s, int off, int len) | 写一个字符串的一部分 |
void write(char[] cbuf) | 写入字符数组 |
void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
public static void main(String[] args) {
try(
//覆盖管道 执行多次就清空上次的内容
Writer writer = new FileWriter("D:\\桌面\\文档\\7788.txt");//文件会自动生成
//追加数据的管道 执行多次内容会拼接到后面
Writer writer1 = new FileWriter("D:\\桌面\\文档\\8899.txt", true);//文件会自动生成
) {
//void write(int c) 写一个字符
writer.write('卡');
writer.write('莎');
writer.write(97);
//换行
writer.write("\r\n");
//void write(String s) 写一个字符串
writer.write("泰坦");
//换行
writer.write("\r\n");
//void write(String s, int off, int len) 写一个字符串的一部分
writer.write("张飞吃豆芽", 0, 2);
//换行
writer.write("\r\n");
//void write(char[] cbuf) 写入字符数组
char[] c = {'欢', '宇', '麦', '朵'};
writer.write(c);
//void write(char[] cbuf, int off, int len) 写入字符数组的一部分
writer.write(c, 0, 2);
} catch (Exception e) {
e.printStackTrace();
}
}
字符输出流写出数据后,必须刷新流( flush()方法 ),或者关闭流(包含刷新操作),写出去的数据才能生效(刷新后流还可以继续使用,关闭流后流就不能继续使用。)
方法名称 | 说明 |
public void flush() throws IOException | 刷新流,将内存中缓存的数据写到文件中 |
public void close() throws IOException | 关闭流操作。包括刷新流 |
6. 缓冲流
对原始数据进行包装,以提高原始流读写数据的性能。
(1) 字节缓冲流
作用:字节缓冲输入流自带了8kb(8192)缓冲池;字节缓冲输出流也自带8kb缓冲池
构造器 | 说明 |
public BufferedInputStream(InputStream is) | 把低级的字节输入流包装成一个高级的缓冲字节输入流,从而提高读数据的性能 |
public BufferedOutputStream(OutputStream os) | 把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能 |
public static void main(String[] args) {
//复制文件
try(
InputStream is = new FileInputStream("D:\\桌面\\文档\\1112233.txt");
//public BufferedInputStream(InputStream is) 把低级的字节输入流包装成一个高级的缓冲字节输入流,从而提高读数据的性能
InputStream bis = new BufferedInputStream(is, 8192 * 2);//16kb
//public BufferedOutputStream(OutputStream os) 把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能
OutputStream os = new FileOutputStream("D:\\桌面\\文档\\11122334455.txt");
OutputStream bos = new BufferedOutputStream(os,8192 * 2);//16kb
){
//创建字节数组 转移字节数据
byte[] b = new byte[1024];
//从字节输入流中读取数据,写到字节输出流 读多少写多少
int len = 0;
while ((len = bis.read(b)) != -1) {
bos.write(b, 0, len);
}
}catch (Exception e){
e.printStackTrace();
}
}
(2) 字符缓冲流
① BufferedReader(字符缓冲输入流)
作用:自带8KB(8192)的字符缓冲池,可以提高字符输入流取字符数据的性能
构造器 | 说明 |
public BufferedReader(Reader r) | 把低级的字符输入流包装成字符缓冲输入流管道,从而提高字符输入流读字符的性能 |
字符缓冲输入流新增的方法 | |
public String readLine() | 读取一行数据返回,如果没有数据可读,返回null |
public static void main(String[] args) {
try (
Reader reader1 = new FileReader("D:\\桌面\\文档\\11122.txt");//aua卡莎墨菲特卡莎墨菲特 aua卡莎墨菲特卡莎墨菲特
//public BufferedReader(Reader r) 把低级的字符输入流包装成字符缓冲输入流管道,从而提高字符输入流读字符的性能
BufferedReader br1 = new BufferedReader(reader1);
) {
/*char[] buf = new char[4];
int len;//记记录每次读取多少字符
while ((len = br1.read(buf)) != -1) {
System.out.print(new String(buf, 0, len));//aua卡莎墨菲特卡莎墨菲特 aua卡莎墨菲特卡莎墨菲特
}*/
/*System.out.println(br1.readLine());//aua卡莎墨菲特卡莎墨菲特
System.out.println(br1.readLine());//aua卡莎墨菲特卡莎墨菲特
System.out.println(br1.readLine());//null*/
String line1;//记录每次读取的一行数据
while ((line1 = br1.readLine()) != null) {
System.out.println(line1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
② BufferedWriter(字符缓冲输出流)
作用:自带8KB(8192)的字符缓冲池,可以提高字符输出流写字符数据的性能
构造器 | 说明 |
public BufferedWriter(Writer r) | 把低级的字符输出流包装成一个高级的缓冲字符输出流的管道,,从而提高字符输出流写字符的性能 |
字符缓冲输出流新增的方法 | |
public void newLine() | 换行 |
public static void main(String[] args) {
try(
//追加数据的管道 执行多次内容会拼接到后面
Writer writer = new FileWriter("D:\\桌面\\文档\\8899.txt", true);//文件会自动生成
//public BufferedWriter(Writer r) 把低级的字符输出流包装成一个高级的缓冲字符输出流的管道,,从而提高字符输出流写字符的性能
BufferedWriter bufferedWriter = new BufferedWriter(writer);
) {
bufferedWriter.write('卡');
bufferedWriter.write('莎');
bufferedWriter.write(97);
//换行
bufferedWriter.newLine();
bufferedWriter.write("张飞吃豆芽");
} catch (Exception e) {
e.printStackTrace();
}
}
7. 转换流
问题:不同编码读取时会乱码:
如果代码编码和被读取的文本文件的编码是一致的,使用字符流读取文本文件不会出现乱码
如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件就会出现乱码
① 字符输入转换流 InputStreamReader
解决不同编码时,字符流读取文本乱码的问题:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流就不会乱码了。
构造器 | |
public InputStreamReader(InputStream is) | 把原始的字节输入流,按照代码默认编码转成字符输入流(与直接用FileReader的效果一样) |
public InputStreamReader(InputStream is, String charset) | 把原始的字节输入流,按照指定的字符集编码转成字符输入流 |
public static void main(String[] args) {
//public InputStreamReader(InputStream is, String charset) 把原始的字节输入流,按照指定的字符集编码转成字符输入流
try(
FileInputStream fis = new FileInputStream(("D:\\桌面\\文档\\a卡莎.txt"));//a卡莎a卡莎a卡莎a卡莎a卡莎a卡莎
Reader isr = new InputStreamReader(fis, "UTF-8");
) {
//使用字符缓冲输入流读取
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);//a卡莎a卡莎a卡莎a卡莎a卡莎a卡莎
}
} catch (Exception e) {
e.printStackTrace();
}
}
② 字符输出转换流 OutputStreamWriter
控制写出去的字符使用什么字符集编码-使用较少:获取字节输出流,在按照指定的字符集编码将其转换成字符输出流,写出去的字符就会用该字符集编码了
构造器 | 说明 |
public OutPutStreamWriter(OutputStream os) | 可以把原始的字节输出流,按照代码默认编码转换成字符输出流 |
public OutPutStreamWriter(OutputStream os, String charset) | 可以把元素的字节输出流,按照指定编码转换成字符输出流 |
public static void main(String[] args) {
//会清空之前的数据
try(
//public OutPutStreamWriter(OutputStream os, String charset) 可以把元素的字节输出流,按照指定编码转换成字符输出流
OutputStream outputStream = new FileOutputStream("D:\\桌面\\文档\\963.txt");//文件自动生成
Writer writer = new OutputStreamWriter(outputStream, "GBK");
//包装成缓冲字符输出流
BufferedWriter bufferedWriter = new BufferedWriter(writer);
) {
bufferedWriter.write("张飞");
bufferedWriter.newLine();
bufferedWriter.write("卡莎A");
bufferedWriter.newLine();
bufferedWriter.write("泰坦");
} catch (Exception e) {
e.printStackTrace();
}
}
8. 打印流
作用:打印流可以实现更方便、更高效的打印数据出去,能实现打印啥就是啥
① 字节输出流 PrintStream
构造器 | 说明 |
public PrintStream(OutputStream/File/String) | 打印流直接通向字节输出流/文件/文件路径 |
public PrintStream(String fileName, Charset charset) | 指定写出去的字符编码 |
public PrintStream(OutputStream out, boolean autoFlush) | 指定自动刷新 |
public PrintStream(OutputStream out, boolean autoFlush, String encoding) | 指定自动刷新,并指定字符编码 |
方法 | 说明 |
public void println(Xxx xxx) | 打印任何类型的数据出去 |
public void write(int/byte[]/byte[]一部分) | 可以支持写字节数据出去 |
public static void main(String[] args) {
//public PrintStream(OutputStream/File/String) 打印流直接通向字节输出流/文件/文件路径.
try(
PrintStream printStream = new PrintStream("D:\\桌面\\文档\\852.txt");//文件自动生成
PrintStream printStream1 = new PrintStream("D:\\桌面\\文档\\852.txt", "UTF-8");
) {
printStream.println("卡车");
printStream.println("卡啥");
printStream.println("卡卡");
printStream.println(96.3);
printStream.println(true);
printStream.println(97);
printStream.write(98);//b
} catch (Exception e) {
e.printStackTrace();
}
}
② 字符输出流 PrintWriter
构造器 | 说明 |
public PrintWriter(OutputStream/Writer/File/String) | 打印流直接通向字节输出流/文件/文件路径 |
public PrintWriter(String fileName, Charset charset) | 指定写出去的字符编码 |
public PrintWriter(OutputStream out/Writer, boolean autoFlush) | 指定自动刷新 |
public PrintWriter(OutputStream out, boolean autoFlush, String encoding) | 指定自动刷新,并指定字符编码 |
方法 | 说明 |
public void println(Xxx xxx) | 打印任何类型的数据出去 |
public void write(int/String/char[]/..) | 可以支持写字符数据出去 |
public static void main(String[] args) {
//public PrintStream(OutputStream/File/String) 打印流直接通向字节输出流/文件/文件路径.
try(
PrintWriter printWriter = new PrintWriter("D:\\桌面\\文档\\741.txt");//文件自动生成
PrintWriter printWriter1 = new PrintWriter("D:\\桌面\\文档\\852.txt", "UTF-8");
//追加
PrintWriter printWriter2 = new PrintWriter(new FileOutputStream("D:\\桌面\\文档\\852.txt", true));
) {
printWriter.println("卡车");
printWriter.println("卡啥");
printWriter.println("卡卡");
printWriter.println(96.3);
printWriter.println(true);
printWriter.println(97);
printWriter.write(98);//b
} catch (Exception e) {
e.printStackTrace();
}
}
③ PrintStream和PrintWriter的区别
(1) 打印数据的功能是一样的:方便高效
(2) PrintStream继承自字节输出流OutputStream, 因此支持写字节数据的方法
(3) PrintWriter继承自字符输出流Writer,因此支持写字符数据的方法
④ 打印流的应用
输出语句的重定向:可以把输出语句的打印位置改到某个文件中去;
public static void main(String[] args) {
//输出语句的重定向:可以把输出语句的打印位置改到某个文件中去;
//打印到控制台
System.out.println("卡莎");
System.out.println("泰坦");
System.out.println("霞");
System.out.println("洛");
//打印到文件
try (
PrintStream printStream = new PrintStream("D:\\桌面\\文档\\159.txt");
){
//把系统默认的打印流对象改成自己设置的打印流
System.setOut(printStream);
System.out.println("卡莎");
System.out.println("泰坦");
System.out.println("霞");
System.out.println("洛");
} catch (Exception e) {
e.printStackTrace();
}
}
9. 数据流
① 数据输出流 DataOutputStream
允许把数据和其类型一并写出去。
构造器 | 说明 |
public DataOutputStream(OutputStream out) | 创建新数据输出流包装基础的字节输出流 |
方法 | 说明 |
public final void writeByte(int v) throws IOException | 将byte类型的数据写入基础的字节输出流 |
public final void writeInt(int v) throws IOException | 将int类型的数据写入基础的字节输出流 |
public final void writeDouble(Double v) throws IOException | 将double类型的数据写入基础的字节输出流 |
public final void writeUTF(String str) throws IOException | 将字符串数据以UTF-8编码成字节写入基础的字节输出流 |
public void write(int/byte[]/byte[]一部分) | 支持写字节数据出去 |
② 数据输入流 DataInputStream
用于读取数据输出流写出去的数据。
构造器 | 说明 |
public DataInputStream(InputStream is) | 创建新数据输入流包装基础的字节输入流 |
方法 | 说明 |
public final byte readByte() throws IOException | 读取字节数据返回 |
public final int readInt() throws IOException | 读取int类型的数据返回 |
public final double readDouble() throws IOException | 读取doublet类型的数据返回 |
public final String readUTF() throws IOException | 读取字符串数据(UTF-8)返回 |
public int readInt() / read(byte[]) | 支持读字节数据进来 |
public static void main(String[] args) {
try (
//public DataOutputStream(OutputStream out) 创建新数据输出流包装基础的字节输出流
OutputStream out = new FileOutputStream("D:\\桌面\\文档\\753.txt");//文件自动生成
DataOutputStream dos = new DataOutputStream(out);
//public DataInputStream(InputStream is) 创建新数据输入流包装基础的字节输入流
InputStream inputStream = new FileInputStream("D:\\桌面\\文档\\753.txt");
DataInputStream dis = new DataInputStream(inputStream);
){
//将数据写入到文件
dos.writeInt(97);
dos.writeDouble(97.5);
dos.writeBoolean(false);
dos.writeUTF("卡莎吃豆芽");
//将数据从文件读取
// --一定要与写进去的数据类型对应 否则或报错
System.out.println(dis.readInt());
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
System.out.println(dis.readUTF());
} catch (Exception e) {
e.printStackTrace();
}
}
10. 序列化流
① 对象序列化 ObjectOutputStream
把Java对象写入到文件中去。对象如果要参与序列化,必须实现序列化接口(
implements Serializable);transient 修饰的成员遍历将不参与序列化;
构造器 | 说明 |
public ObjectOutputStream(OutputStream out) | 创建对象字节输出流,包装基础的字节输出流 |
方法 | 说明 |
public final void writeObject(Object o) throws IOException | 把对象写出去 |
② 对象序反列化 ObjectInputStream
把文件中的Java对象读到内存中。
构造器 | 说明 |
public ObjectInputStream(InputStream out) | 创建对象字节输入流,包装基础的字节输入流 |
方法 | 说明 |
public final Object readObject(Object o) | 把存储在文件中的Java对象读出来 |
//对象如果要参与序列化,必须实现序列化接口(implements Serializable)
public class Student implements Serializable {
private String name;
private int age;
//transient 这个成员遍历将不参与序列化
private transient double score;
public Student() {
}
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Double.compare(score, student.score) == 0 && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, score);
}
}
public static void main(String[] args) {
//创建一个学生对象
Student student = new Student("卡莎", 18, 97.5);
try (
// //public ObjectOutputStream(OutputStream out) 创建对象字节输出流,包装基础的字节输出流
OutputStream outputStream = new FileOutputStream("D:\\桌面\\文档\\student.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
//public ObjectInputStream(InputStream out) 创建对象字节输入流,包装基础的字节输入流
InputStream inputStream = new FileInputStream("D:\\桌面\\文档\\student.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
){
//public final void writeObject(Object o) throws IOException 把对象写出去
objectOutputStream.writeObject(student);
//public final Object readObject(Object o) 把存储在文件中的Java对象读出来
Student s = (Student) objectInputStream.readObject();
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
如果一次要序列化多个对象,可以用ArrayList存储多个对象,然后直接对集合进行序列化就行,ArrayList已经实现了序列化接口Serializable。
三. IO框架
框架:解决某类问题,编写的一套类、接口等,可以理解成一个半成品,大多数框架都是第三方研发的。
好处:在框架的基础上开发,可以得到优秀的软件架构,提高开发效率
框架的形式:一般是把类、接口等编译成class形式,在压缩成一个.jar结尾的文件发行
IO框架:封装了Java提供的对文件、数据进行操作的代码,对外提供了更简单的方式来对文件进行操作。
1. Commons-io
Commons-io是apache开源基金组织提供的一组有关IO操作的小框架,目的是提高IO流的开发效率
FileUtils类提供的部分方法展示 | 说明 |
public static void copyFile(File srcFile, File destFile) | 复制文件。 |
public static void copyDirectory(File srcDir,File destDir) | 复制文件夹 |
public static void deleteDirectory(File directory) | 删除文件夹 |
public static string readFileTostring(File file, string encoding) | 读数据 |
public static void writestringToFile(File file,String data, string charname, boolean append) | 写数据 |
I0Utils类提供的部分方法展示 | 说明 |
public static int copy(Inputstream inputstream, OutputStream outputStream) | 复制文件 |
public static int copy(Reader reader, Writer writer) | 复制文件 |
public static void write(string data, 0utputstream output, String charsetName) | 写数据 |
public static void main(String[] args) throws Exception {
//Commons-io
FileUtils.copyFile(new File("D:\\桌面\\文档\\001.txt"), new File("D:\\桌面\\文档\\002.txt"));
}