D:\code\黑马\code\IO-app
File:读写,操作文件
IO流:读写、操作文件中的数据
File是java.io.包下的类,File类的对象用于代表当前操作系统中的文件(可以是文件、或文件夹)
File类只能对文件本身进行操作,不能读写文件里面存储的数据
构造器 | 说明 |
---|---|
public File(String pathname) | 根据文件路径创建文件对象 |
public File(String parent, String child) | 根据父路径和子路径名字创建文件对象 |
public File(File parent, String child) | 根据父路径对应文件对象和子路径名字创建文件对象 |
public class Test1 {
public static void main(String[] args) {
//创建File对象的三种方式
//1. 通过文件路径创建File对象
//public File(String pathname)
File f1 = new File("E:/A/a.txt");
System.out.println(f1);//E:\A\a.txt
//2. 通过父路径和子路径创建File对象
//public File(String parent, String child)
File f2 = new File("E:/A", "a.txt");
System.out.println(f2);//E:\A\a.txt
//3. 通过父路径对象和子路径创建File对象
//public File(File parent, String child)
File parentFile = new File("E:/A");
File f3 = new File(parentFile, "a.txt");
System.out.println(f3);//E:\A\a.txt
}
}
public class Test2 {
public static void main(String[] args) {
//File对象既可以代表文件、也可以代表文件夹。
//File对象代表文件
File f1 = new File("E:/A/a.txt");
System.out.println(f1.exists());//true
//File对象代表文件夹
File f2 = new File("E:/A");
System.out.println(f2.exists());//true
//Fil封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的。
File f3 = new File("E:/A/dw");//路径下的文件夹dw不存在
System.out.println(f3.exists());//false
File f4 = new File("E:/A/d.txt");//路径下的文件d.txt不存在
System.out.println(f4.exists());//false
}
}
public class Test3 {
public static void main(String[] args) {
//路径分隔符三种写法
//1.使用'/'表示路径分隔符
File f1 = new File("E:/A/a.txt");
System.out.println(f1);//E:\A\a.txt
//2.使用'\\'表示路径分隔符
File f2 = new File("E:\\A\\a.txt");
System.out.println(f2);//E:\A\a.txt
//3.使用File.separator表示路径分隔符
File f3 = new File("E:" + File.separator + "A" + File.separator + "a.txt");
System.out.println(f3);//E:\A\a.txt
}
}
public class Test4 {
public static void main(String[] args) {
//绝对路径和相对路径
//1. 绝对路径:从盘符开始的路径,这种路径一般都是写死的。
File f1 = new File("D:\\code\\黑马\\code\\IO-app\\src\\a.txt");
System.out.println(f1.exists());//true
//2. 相对路径:相对于当前项目而言的,这种路径建议写活的。
File f2 = new File("src\\a.txt");
System.out.println(f2.exists());//true
//如果直接在项目下,不在src下,直接写a.txt即可。
}
}
方法 | 说明 |
---|---|
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 class Test5 {
public static void main(String[] args) {
//判断文件类型、获取文件信息的方法
File file1 = new File("src/a.txt");//相对路径
File file3 = new File("D:\\code\\黑马\\code\\IO-app\\src\\a.txt");//绝对路径
File file2= new File("src");
//1.判断路径是否存在
//public boolean exists( ),存在返回true,不存在返回false
System.out.println(file1.exists());//true
//2.判断是否是文件
//public boolean isFile( ),是文件返回true,不是文件返回false
System.out.println(file1.isFile());//true
//3.判断是否是文件夹
//public boolean isDirectory( ),是文件夹返回true,不是文件夹返回false
System.out.println(file1.isDirectory());//false
System.out.println(file2.isDirectory());//true
//4.获取文件或文件夹名
//public String getName( ),返回文件或文件夹名
System.out.println(file1.getName());//a.txt
System.out.println(file2.getName());//src
//5.获取文件或文件夹的大小
//public long length( ),返回文件或文件夹的大小,单位是字节
System.out.println(file1.length());//6
//6.获取文件或文件夹的最后修改时间
//public long lastModified( ),返回文件或文件夹的最后修改时间,单位是毫秒
long time = file1.lastModified();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd " +
"HH:mm:ss");
System.out.println(simpleDateFormat.format(time));//2023-08-09 11:05:36
//7.获取常见File对象时使用的路径
//public String getPath( ),返回常见File对象时使用的路径
System.out.println(file1.getPath());//src\a.txt
System.out.println(file3.getPath());//D:\code\黑马\code\IO-app\src\a.txt
//8.获取绝对路径
//public String getAbsolutePath( ),返回绝对路径
//无论创建File对象时使用的是绝对路径还是相对路径,都可以使用getAbsolutePath()方法获取绝对路径
System.out.println(file1.getAbsolutePath());//D:\code\黑马\code\IO-app\src\a.txt
System.out.println(file3.getAbsolutePath());//D:\code\黑马\code\IO-app\src\a.txt
}
}
创建文件方法 | 说明 |
---|---|
public boolean createNewFile( ) | 创建一个新的空文件 |
public boolean mkdir( ) | 只能创建一级文件夹 |
public boolean mkdirs( ) | 可以创建多级文件夹 |
删除创建文件方法 | 说明 |
---|---|
public boolean delete( ) | 默认只能删除文件或空文件夹,无法删除非空文件夹,删除后的文件不会放入回收站,不允许使用相对路径 |
public class Test {
public static void main(String[] args) throws IOException {
//1. 创建新的空文件
//public boolean createNewFile( )
//创建成功返回true,如果已有该文件则返回false
File f1 = new File("D:\\code\\黑马\\code\\IO-app\\src\\b.txt");//当前不存在该文件
//创建File对象时传入的必须是绝对路径,相对路径会报错
System.out.println(f1.createNewFile());//true
System.out.println(f1.createNewFile());//false
//第二次创建失败,因为已经存在该文件
//2. 创建空的一级文件夹
//public boolean mkdir( )
//创建成功返回true,如果已有该文件夹则返回false
File f2 = new File("D:\\code\\黑马\\code\\IO-app\\src\\c");
System.out.println(f2.mkdir());//true
System.out.println(f2.mkdir());//false
//如果父目录也不存在,则属于创建二级文件夹,会创建失败
File f3 = new File("D:\\code\\黑马\\code\\IO-app\\src\\d\\e");
System.out.println(f3.mkdir());//false
//3. 创建空的多级文件夹
//public boolean mkdirs( )
//创建成功返回true,如果已有该文件夹则返回false
File f4 = new File("D:\\code\\黑马\\code\\IO-app\\src\\d\\e");
System.out.println(f4.mkdirs());//true
System.out.println(f4.mkdirs());//false
//4. 删除文件或文件夹,如果是文件夹,则必须是空的才能删除
//public boolean delete( )
//删除成功返回true,如果不存在该文件或文件夹或文件夹不为空则返回false
File f5 = new File("D:\\code\\黑马\\code\\IO-app\\src\\a.txt");
System.out.println(f5.delete());//true 删除有内容的文件
File f6 = new File("D:\\code\\黑马\\code\\IO-app\\src\\b.txt");
System.out.println(f6.delete());//true 删除空文件
File f7 = new File("D:\\code\\黑马\\code\\IO-app\\src\\c");
System.out.println(f7.delete());//true 删除空文件夹
File f8 = new File("D:\\code\\黑马\\code\\IO-app\\src");
System.out.println(f8.delete());//false 删除非空文件夹
}
}
方法(只能遍历一级目录) | 说明 |
---|---|
public String[ ] list( ) | 获取当前目录下所有的"一级文件名称“到一个字符串数组中去返回 |
public File[ ] listFiles( ) | 获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回 |
public class Test6 {
public static void main(String[] args) {
//获取当前目录下所有的"一级文件名称“到一个字符串数组中去返回
//返回所有当前路径文件夹下的文件夹和文件(隐藏文件也会返回),不包含子文件夹中的内容
//public String[] list( )
File f1 = new File("src\\file");
String[] names = f1.list();
System.out.println(Arrays.toString(names));
//[Test.java, Test1.java, Test2.java, Test3.java,
// Test4.java, Test5.java, Test6.java]
//获取当前目录下所有的"一级文件对象”到一个File数组中去返回
//public File[] listFiles( )
File[] files = f1.listFiles();
System.out.println(Arrays.toString(files));//数组中的元素是File对象
//[src\file\Test.java, src\file\Test1.java, src\file\Test2.java,
// src\file\Test3.java, src\file\Test4.java, src\file\Test5.java,
// src\file\Test6.java]
System.out.println(files[0].getAbsolutePath());
//D:\code\黑马\code\IO-app\src\file\Test.java
}
}
使用ListFiles方法时的注意事项:
案例
public class Test8 {
public static void main(String[] args) {
//将文件夹下的视频的序号从19开始重新命名
//原文件格式: 1、... .mp4 2、... .mp4 3、... .mp4等
//创建文件夹对象
File f = new File("D:\\Java\\video");//该文件夹下有视频文件
//获取文件夹下的所有文件
File[] videos = f.listFiles();
for (File video : videos) {
String name = video.getName();
String index = name.substring(0, name.indexOf("、"));
String lastName = name.substring(name.indexOf("、"));
String newName = (Integer.parseInt(index) + 18) + lastName;
//重命名
video.renameTo(new File(f,newName));
}
}
}
概念
递归的形式
递归三要素(解题的关键)
注意的问题
递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误
public class tests {
public static void main(String[] args) {
say();//直接递归
say1();//间接递归
}
//直接递归,下面代码会报错,因为递归太深了,没有出口,栈内存溢出
public static void say(){
System.out.println("say");
say();
}
//间接递归,同样会报错,因为递归太深了,没有出口,栈内存溢出
public static void say1(){
System.out.println("say1");
say2();
}
public static void say2(){
say1();
}
}
案例1:计算n的阶乘
需求:计算n的阶乘
分析:
public class Test9 {
public static void main(String[] args) {
int reuslt = getJieCheng(5);
System.out.println(reuslt);
}
public static int getJieCheng(int n) {
if (n == 1) {
return 1;
}else {
return n * getJieCheng(n - 1);
}
}
}
案例2:计算1到n的和
需求:计算1到n的和
分析:
public class Test9 {
public static void main(String[] args) {
int reuslt = getSum(5);
System.out.println(reuslt);
}
public static int getSum(int n) {
if (n == 1) {
return 1;
}else {
return n + getSum(n - 1);
}
}
}
案例3:猴子吃桃问题
需求:
分析:
public class Test9 {
public static void main(String[] args) {
int reuslt = peach(1);
System.out.println(reuslt);
}
public static int peach(int n){
if (n == 10) {
return 1;
}else {
return (peach(n + 1) + 1) * 2;
}
}
}
案例4:啤酒问题
啤酒2元一瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶,请问10元可以喝多少瓶?
public class T1 {
public static void main(String[] args) {
buy(10,0,0,0);
//参数列表:钱数,总瓶数,剩余盖子数,剩余空瓶数
}
public static void buy(int money,int allNumber,int coverNumber,int bottleNumber ){
int buyBottle = money / 2;//用钱买的瓶数
money %= 2;
allNumber += buyBottle;//总瓶数加上用钱买的瓶数
coverNumber += buyBottle;//剩余盖子数加上用钱买的瓶数
bottleNumber += buyBottle;//剩余空瓶数加上用钱买的瓶数
if (coverNumber >= 4){//如果剩余盖子数大于4,可以换瓶
buyBottle = coverNumber / 4;//用盖子换的瓶数
allNumber += buyBottle;//总瓶数等于总瓶数加上用盖子换的瓶数
coverNumber = coverNumber % 4 + buyBottle;
//剩余盖子数等于剩余盖子数除以4的余数加上用盖子换的瓶数
bottleNumber += buyBottle;//剩余空瓶数等于剩余空瓶数加上用盖子换的瓶数
}
if (bottleNumber >= 2){//如果剩余空瓶数大于2,可以换瓶
buyBottle = bottleNumber / 2;//用空瓶换的瓶数
allNumber += buyBottle;//总瓶数等于总瓶数加上用空瓶换的瓶数
bottleNumber = bottleNumber % 2 + buyBottle;
//剩余空瓶数等于剩余空瓶数除以2的余数加上用空瓶换的瓶数
coverNumber += buyBottle;//剩余盖子数等于剩余盖子数加上用空瓶换的瓶数
}
if (coverNumber >= 4 || bottleNumber >= 2){
//如果剩余盖子数大于4或者剩余空瓶数大于2,继续买
buy(money,allNumber,coverNumber,bottleNumber);
}else {
System.out.printf("一共买了 %d 瓶%n", allNumber);
System.out.println("剩余盖子数:" + coverNumber);
System.out.println("剩余空瓶数:" + bottleNumber);
return;
}
}
}
需求:从E盘中搜索“System4.0.exe”文件,找到后输出所在位置并启动
分析:
public class Test10 {
public static void main(String[] args) throws Exception {
File file = new File("E:\\");
findFile(file, "System4.0.exe");
}
public static void findFile(File file, String name) throws Exception {
//判断第一次传入的file是否存在或是否为文件,如果为文件并且文件名与name相同,则输出路径并打开
if(!file.exists() || file == null || file.isFile()){
if(file.isFile() && file.getName().equals(name)){
System.out.println(file.getAbsolutePath());
Runtime runtime = Runtime.getRuntime();
//"cmd /c "是防止权限不够,无法打开文件
runtime.exec("cmd /c " + file.getAbsolutePath());
}
return;
}
//当前传入的一定是一个文件夹
File[] fs = file.listFiles();//获取当前文件夹下的所有文件和文件夹
if (fs != null){
for (File f : fs) {//遍历
if (f.isFile()){//如果是文件
if(f.getName().equals(name)){//如果文件名与name相同,则输出路径并打开
System.out.println(f.getAbsolutePath());
Runtime runtime = Runtime.getRuntime();
runtime.exec("cmd /c " + f.getAbsolutePath());
}
}else {
//如果是文件夹,重复上面的操作
findFile(f, name);
}
}
}
}
}
需求:删除非空文件夹
分析
public class T {
public static void main(String[] args) {
File file = new File("E:\\B");
delectDic(file);
}
public static void delectDic(File file){
if (!file.exists() || file == null){
return;//文件不存在
}
if (file.isFile()){//存在且为文件
file.delete();
}else {
//存在且一定为文件夹
if (file == null){
return;//没有删除的权限,直接return
}
File[] files = file.listFiles();
// if (files.length == 0){
// file.delete();
// return;
// }
for (File f : files) {
if (f.isFile()){
f.delete();
}else {
delectDic(f);//删除下级目录
}
}
file.delete();//删除自己
//无论当前文件夹下是否为空,经过上面的for后,
//都已经没有下一级文件了,所以无需写上面注释的代码
}
}
}
用于读写数据(可以读写文件,或网络中的数据.…)
位(bit):计算机内部数据存储的最小单位,用b表示。11001100是一个八位二进制数
字节(byte): 计算机数据处理的基本单位,用B表示
UTF-8编码格式(二进制形式,必须以表格中对应的数字开头) |
---|
1个字节的表示形式:0xxxxxxx(ASCll字符集) |
2个字节的表示形式:110xxxxx 10xxxxxx |
3个字节的表示形式:1110xxxx 10xxxxxx 10xxxxxx |
4个字节的表示形式:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
String提供的编码方法 | 说明 |
---|---|
byte[ ] getBytes( ) | 使用平台的默认字符集将该String编码为字节数组 |
byte[ ] getBytes( String charsetName) | 使用入参指定的字符集将该String编码为字节数组 |
String提供的解码方法(构造器) | 说明 |
---|---|
String( byte[ ] bytes ) | 使用平台的默认字符集将输入的字节数组解码为字符串 |
String( byte[ ] bytes, String charsetName) | 使用入参指定的字符集将输入的字节数组解码为字符串 |
public class T2 {
public static void main(String[] args) throws Exception {
//字符串编码
//1.使用平台的默认字符集将该String编码为字节数组
//byte[ ] getBytes( )
String s = "a你c";
byte[] bytes1 = s.getBytes();
System.out.println(Arrays.toString(bytes1));
//[97, -28, -67, -96, 99]
//第一个代表a的ASCII码,后面三个代表你的UTF-8编码,最后一个代表c的ASCII码
//正常应该用二进制表示,这里自动转换成了十进制表示
//2.使用指定的字符集将该String编码为字节数组
//byte[ ] getBytes(String charsetName)
byte[] bytes2 = s.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));
//[97, -60, -29, 99]
//GBK中ASCII码占一个字节,中文占两个字节
//第一个代表a的ASCII码,后面两个代表汉字你的GBK编码,最后一个代表c的ASCII码
//字符串解码
//1.使用平台的默认字符集将字节数组解码为String
//String(byte[] bytes)
String s1 = new String(bytes1);
System.out.println(s1);//a你c
//2.使用指定的字符集将字节数组解码为String
//String(byte[] bytes, String charsetName)
String s2 = new String(bytes1, "GBK");
System.out.println(s2);//a浣燾,因为编码与解码方式不同
String s3 = new String(bytes2, "GBK");
System.out.println(s3);//a你c,因为编码与解码方式相同
}
}
适用于一切文件的文件的复制、转移;不适合读取中文内容输出。
作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去。
构造器 | 说明 |
---|---|
public FileInputstream(File file) | 根据输入的File对象创建字节输入流管道与源文件接通 |
public FileInputstream(String pathname) | 根据输入的路径创建字节输入流管道与源文件接通 |
public class Test1 {
public static void main(String[] args) throws FileNotFoundException {
//1.根据输入的File对象创建字节输入流管道与源文件接通
//public FileInputstream(File file)
File file = new File("src/a.txt");
InputStream fis1 = new FileInputStream(file);
//2.根据输入的字符串路径创建字节输入流管道与源文件接通(推荐使用)
//public FileInputStream(String path)
InputStream fis2 = new FileInputStream("src/a.txt");
}
}
常用方法 | 说明 |
---|---|
public int read( ) | 每次读取一个字节返回,如果发现没有数据可读会返回-1 |
public int read(byte[ ] buffer) | 每次用一个字节数组去读取数据,返回字节数组读取了多少个字节,如果发现没有数据可读会返回-1 |
public byte[ ] readAllBytes( ) | 直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回 |
public class Test1 {
public static void main(String[] args) throws Exception {
//a.txt中的内容:abcddwadawdna我
InputStream fis = new FileInputStream("src/a.txt");
//每次读取一个字节
//public int read( )
//每次返回一个字节即八位二进制数,读取到文件末尾返回-1
int temp;
while ((temp = fis.read()) != -1){
System.out.print((char) temp);//abcddwadawdna我
//如果不使用(char)强制转换,输出的是八位的二进制数转换成的十进制数
//不使用(char)强制转换的十进制数为
// 97 98 99 100 100 119 97 100 97 119 100 110 97 230 136 145
}
/*
public int read( )方法的缺点:
*/
//1.每次只能读取一个字节,效率低,因为需要频繁的读取磁盘,
// 每读取一个字节就要读取一次磁盘
//2.读取的如果是中文,会出现乱码,不可避免
//因为使用UTF-8时一个中文占三个字节,而一个字节只能读取一个字节,
//一个中文被强制拆分成三个字节,所以会出现乱码
//上面的输出结果中230 136 145对应的二进制应该表示”我“,
//但是被拆分成了三个字节分开读,导致了乱码我
//关闭流
fis.close();
}
}
缺点
public class Test2 {
public static void main(String[] args) throws Exception {
//a.txt中的内容:abcddw的ada哈哈哈wdna我
InputStream inputStream = new FileInputStream("src/a.txt");
//使用public int read(byte[ ] buffer)每次读取自定义数量的字节
byte[] buffer = new byte[6];//每次读取6个字节,一个字节表示8位二进制数
int len;//每次读取的字节数
while ((len = inputStream.read(buffer)) != -1){
String str = new String(buffer,0,len);
System.out.print(str);
//结果:abcddw的ada哈哈哈wdna我
}
inputStream.close();
}
}
/*
深度理解public int read(byte[ ] buffer)方法给byte数组赋值的机制
如果读取的字节数达不到数组的长度,剩余长度的数组保持上次的值
使用String的public String(byte[] bytes,int offset,int length)构造方法可以解决输出重复的问题
*/
public class Test4 {
public static void main(String[] args) throws Exception {
//a.txt中的内容:abcdefd
InputStream inputStream = new FileInputStream("src/a.txt");
//给byte数组赋值的机制是将读到的字节赋值给数组的每一个元素,
// 但是如果读到的字节数不足数组长度时,剩余的元素不会被赋值,会保持上一次赋值的状态
byte[] bytes = new byte[5];
int len1 = inputStream.read(bytes);
System.out.println(new String(bytes));//abcde
System.out.println(len1);//5
System.out.println(Arrays.toString(bytes));//[97, 98, 99, 100, 101]
int len2 = inputStream.read(bytes);
System.out.println(new String(bytes));
//fbcde,后面的元素没有被赋值,保持上一次的状态
System.out.println(len2);//2
System.out.println(Arrays.toString(bytes));
//[102, 100, 99, 100, 101],后面的元素没有被赋值,保持上一次的状态
//保证输出正确,不会输出重复内容的解决方案
//每次根据获取到的字节长度创建用于解码的String对象
System.out.println(new String(bytes,0,len2));//fd
inputStream.close();
}
}
优点:解决了每次读取单个文件时效率低的问题,读取性能得到了提升。因为原来读30个字节需要操作系统调用30次磁盘,现在则是根据传入数组的长度,如果数组长度为3,则调用10次磁盘即可,因为一次读取3个字节
缺点:中文乱码问题还是没有得到解决
方式一:使用public int read(byte[ ] buffer),自定义数组长度为文件中数据的字节数
方式二:使用**public byte[ ] readAllBytes( )**直接返回所有的字节
public class Test3 {
public static void main(String[] args) throws Exception {
//a.txt的内容:abcddw的ada哈哈哈wdna我
//一次读取所有字节
//方式一:使用public int read(byte[ ] buffer)
InputStream inputStream = new FileInputStream("src/a.txt");
long size = new File("src/a.txt").length();
//获取文件的大小,单位是字节
byte[] buffer1 = new byte[(int) size];
//创建一个和文件大小一样的字节数组
int len = inputStream.read(buffer1);
//将文件中的内容读取到字节数组中,返回值为读取到的字节数
System.out.println(new String(buffer1));
//将字节数组解码成字符串输出,使用默认的UTF-8解码
//输出结果:abcddw的ada哈哈哈wdna我
inputStream.close();
//方式二:使用public byte[ ] readAllBytes( )直接返回所有的字节
InputStream inputStream2 = new FileInputStream("src/a.txt");
//必须重写定义一个FileInputStream对象,
//因为上面的FileInputStream对象已经读取到文件末尾了,不能再读取了
byte[] buffer2 = inputStream2.readAllBytes();//JDK9之后才有
System.out.println(new String(buffer2));
//将字节数组解码成字符串输出,使用默认的UTF-8解码
//输出结果:abcddw的ada哈哈哈wdna我
inputStream2.close();
}
}
优点:读取速度得到了明显提升并且解决了读取中文乱码的问题
缺点:如果文件过大,就会导致创建的字节数组也会过大,可能会导致内存溢出
作用:以内存为基准,把内存中的数据以字节的形式写出到文件中
构造器 | 说明 |
---|---|
public FileOutputStream(File file) | 创建字节输出流管道与源文件对象接通,默认会清空原来文件中数据 |
public FileOutputStream(String filepath) | 创建字节输出流管道与源文件路径接通,默认会清空原来文件中数据 |
public FileOutputStream(File file, boolean append) | 创建字节输出流管道与源文件对象接通,如果后面参数为true则允许追加数据,不会清空原有数据 |
public FileOutputStream(String filepath, boolean append) | 创建字节输出流管道与源文件路径接通,如果后面参数为true则允许追加数据,不会清空原有数据 |
public class Test5 {
public static void main(String[] args) throws Exception {
//public FileOutputStream(String filepath),会覆盖原文件,每次写入都会清空原文件
OutputStream fo1 = new FileOutputStream("src\\B.txt");
fo1.close();
//public FileOutputStream(String filepath, boolean append)
// 如果append为true则不会覆盖原文件,每次写入都会在原文件末尾追加
OutputStream fo2 = new FileOutputStream("src\\B.txt", true);
fo2.close();
}
}
方法 | 说明 |
---|---|
public void write( int a ) | 写一个字节到硬盘指定位置 |
public void write( byte[ ] buffer ) | 写一个字节数组到硬盘指定位置 |
public void write( byte[ ] buffer, int pos , int len) | 写一个字节数组的一部分到硬盘指定位置,pos为开始索引,len为要写入的长度 |
public class Test6 {
public static void main(String[] args) throws Exception {
FileOutputStream fo = new FileOutputStream("src\\B.txt", true);
//常用方法
//1.public void write(int b):写入一个字节
fo.write(97);
fo.write('b');//'b'会被自动转为int类型,对应的ASCII码为98
fo.write('哈');
//'哈'会被自动转为int类型,但是有三个字节,所以只会写入第一个字节,会乱码
//当前文件内容::ab�
//写入回车:\r\n
fo.write("\r\n".getBytes());
//2.public void write(byte[] b):写入一个字节数组
byte[] b1 = "一起传入就不会乱码了".getBytes();
fo.write(b1);
byte[] b2 = {98, 99, 'a'};
fo.write(b2);
fo.write("\r\n".getBytes());
//当前文件内容:
// ab�
//一起传入就不会乱码了bca
//3.public void write(byte[] b, int off, int len):写入一个字节数组的一部分
byte[] b3 = "一起传入就不会乱码了".getBytes();
fo.write(b3, 0, 3);//写入前三个字节,也就是一个字,因为一个字在UTF-8中占三个字节
//当前文件内容:
// ab�
//一起传入就不会乱码了bca一
//一
fo.close();
}
}
将一张图片复制到磁盘的另一个位置
PS:下面的两个程序可以用于复制一切文件
//方法一
public class Test7 {
public static void main(String[] args) throws Exception{
// 读取图片为字节数组
FileInputStream inputStream = new FileInputStream("E:\\Pictures\\Camera Roll" +
"\\1.jpg");
byte[] picture = inputStream.readAllBytes();
// 将读取到的字节数组写入指定路径
FileOutputStream outputStream = new FileOutputStream("src/1.jpg");
outputStream.write(picture);
outputStream.close();
inputStream.close();
}
}
//方法二
public class Test8 {
public static void main(String[] args) throws Exception{
FileInputStream inputStream = new FileInputStream("E:\\Pictures\\Camera Roll" +
"\\1.jpg");
FileOutputStream fileOutputStream = new FileOutputStream("src/2.jpg");
byte[] picture = new byte[1024];// 一次读取1024个字节即1KB
int len;
while ((len = inputStream.read(picture)) != -1) {
fileOutputStream.write(picture, 0, len);
}
fileOutputStream.close();
inputStream.close();
}
}
目的:因为调用流的close( )方法在最后,如果中间代码出现异常会导致程序异常终止,close方法不会被执行,流无法被正常释放
特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非JVM终止。
作用:一般用于在程序执行完成后进行资源的释放操作(专业级做法)
案例:使用try-catch-finally优化上面文件复制案例的代码**(优化后代码过于臃肿)**
//释放资源的标准写法
public class Test8 {
public static void main(String[] args){
FileInputStream is = null;
FileOutputStream os = null;
try {
is = new FileInputStream("E:\\Pictures\\Camera Roll" +
"\\1.jpg");
os = new FileOutputStream("src/2.jpg");
byte[] picture = new byte[1024];// 一次读取1024个字节即1KB
int len;
while ((len = is.read(picture)) != -1) {
os.write(picture, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (os != null) os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (is != null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
作用与try-catch-finally相同,只不过使代码更加简洁
资源对象:资源对象是指资源对象对应的类必须实现AutoCloseable接口并且重写close方法
try-with-resource格式
try(定义资源对象1,定义资源对象2...)
{
方法体
}catch(){
}
注意:
案例:再次改进try-catch-finally优化的代码,减少代码的臃肿
public class Test8 {
public static void main(String[] args){
try (
FileInputStream is = new FileInputStream("E:\\Pictures\\Camera Roll" +
"\\1.jpg");
FileOutputStream os = new FileOutputStream("src/2.jpg");
){
byte[] picture = new byte[1024];// 一次读取1024个字节即1KB
int len;
while ((len = is.read(picture)) != -1) {
os.write(picture, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
自定义资源类
允许自定义资源类,只需要让类实现AutoCloseable接口并且重写close方法接口
//自定义资源类
public class resource implements AutoCloseable{
public void use(){
System.out.println("资源被使用了");
}
@Override
public void close() {
System.out.println("资源被关闭了");
}
}
public class Test9 {
public static void main(String[] args) {
try(
resource s = new resource();
){
s.use();
}catch (Exception e){
e.printStackTrace();
}
}
}
/*
输出结果:
资源被使用了
资源被关闭了
*/
适用于读写文件的内容
构造器与方法与字节流基本一致,但是由于每次读取到的是字符,所以不会出现乱码问题
相当于根据当前文件的编码方式读取字符
作用:以内存为基准,可以把文件中的数据以字符的形式读入到内存中去。
构造器 | 说明 |
---|---|
public FileReader(File file) | 根据输入的File对象创建字符输入流管道与源文件接通 |
public FileReader(String pathname) | 根据输入的路径创建字符输入流管道与源文件接通 |
常用方法 | 说明 |
---|---|
public int read( ) | 每次读取一个字符返回,如果发现没有数据可读会返回-1 |
public int read(char[ ] buffer) | 每次用一个字符数组去读取数据,返回字符数组读取了多少个字符,如果发现没有数据可读会返回-1 |
public class Test1 {
public static void main(String[] args) {
//a.txt中的内容为:ab我的你打c打完了电脑defd
try (
Reader fileReader1 = new FileReader("src/a.txt");
Reader fileReader2 = new FileReader("src/a.txt");
) {
// 每次读取一个字符
// public int read()
// 每次返回一个字符,读取到文件末尾返回-1
int temp;
while((temp = fileReader1.read()) != -1){
System.out.print((char) temp);
//返回的是每个字符对应的十进制数,需要强制转换成char
//结果:ab我的你打c打完了电脑defd
//因为每次读取的是一个字符,所以不会出现乱码问题
}
System.out.println();
// 每次读取一个字符数组
// public int read(char[] buffer)
// 每次返回读取到的字符个数,读取到文件末尾返回-1
char[] buffer = new char[4];//每次读取四个字符
int len;
while ((len = fileReader2.read(buffer)) != -1){
System.out.print(new String(buffer, 0, len));
//输出结果:ab我的你打c打完了电脑defd
}
}catch (Exception e){
e.printStackTrace();
}
}
}
作用:以内存为基准,把内存中的数据以字符的形式写出到文件中
构造器 | 说明 |
---|---|
public FileWriter(File file) | 创建字符输出流管道与源文件对象接通,默认会清空原来文件中数据 |
public FileWriter(String filepath) | 创建字符输出流管道与源文件路径接通,默认会清空原来文件中数据 |
public FileWriter(File file, boolean append) | 创建字符输出流管道与源文件对象接通,如果后面参数为true则允许追加数据,不会清空原有数据 |
public FileWriter(String filepath, boolean append) | 创建字符输出流管道与源文件路径接通,如果后面参数为true则允许追加数据,不会清空原有数据 |
方法 | 说明 |
---|---|
public void write( int a ) | 写一个字符到硬盘指定位置 |
public void write(String str) | 写一个字符串到硬盘指定位置 |
public void write(String str, int off , int len) | 写一个字符串的一部分到磁盘的指定位置 |
public void write( char[ ] buffer ) | 写一个字符数组到硬盘指定位置 |
public void write( char[ ] buffer, int off , int len) | 写一个字符数组的一部分到硬盘指定位置,pos为开始索引,len为要写入的长度 |
public class Test2 {
public static void main(String[] args) {
try (
Writer fileWriter = new FileWriter("src/b.txt")
)
{
//常用方法
//1.public void write(int c),每次写入一个字符
fileWriter.write(97);
fileWriter.write('b');
fileWriter.write('哈');//不会乱码,因为将三个字节打包为一个字符写入
fileWriter.write("\r\n");//写入回车
/*
当前文件内容:ab哈
*/
//2.public void write(String str),每次写入一个字符串
fileWriter.write("字符输出流!\r\n");
/*
当前文件内容:
ab哈
字符输出流!
*/
//3.public void write(String str, int off, int len),每次写入一个字符串一部分
fileWriter.write("字符输出流!\r\n", 2, 6);
//从索引为2的字符开始写入,写入3个字符
/*
当前文件内容:
ab哈
字符输出流!
输出流!
*/
//4. public void write(char[] cbuf),每次写入一个字符数组
char[] chars = {'a', '我', 'c', 97, 'e','\r','\n'};
fileWriter.write(chars);
/*
当前文件内容:
ab哈
字符输出流!
输出流!
a我cae
*/
//5.public void write(char[] cbuf, int off, int len),每次写入字符数组的一部分
fileWriter.write(chars, 1, 3);//从索引为1的字符开始写入,写入3个字符
/*
当前文件内容:
ab哈
字符输出流!
输出流!
a我cae
我ca
*/
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效
在调用write方法将数据写入磁盘,在遇到刷新流( public void flush( ) )或关闭流( public void close( ) )的方法前都会先将write传入的数据先放入缓冲区中,在遇到刷新流或关闭流的方法后才会调用系统的资源将缓冲区中的内容一次写入到磁盘中,这样做可以避免浪费系统资源,提高整体的性能。
刷新流与关闭流的区别
作用:对原始流(字节流、字符流)讲行包装,通过减少磁盘调用量以提高原始流读写数据的性能
字节缓冲输入流和字节缓冲输出流,分别用于包装字节输入流和字节输出流
通过增加缓冲池减少调用磁盘的次数来提高字节流读写数据的性能
方法 | 说明 |
---|---|
public BufferedInputStream( InputStream is ) | 把低级的字节输入流包装成一个高级的缓冲字节输入流,入参为字节输入流对象,继承了所有字节输入流的方法 |
public BufferedOutputStream( OutputStream os ) | 把低级的字节输出流包装成一个高级的缓冲字节输出流,入参为字节输出流对象,继承了所有字节输出流的方法 |
//原始的字节输入输出流拷贝数据的方法
public class Test8 {
public static void main(String[] args){
try (
FileInputStream is = new FileInputStream("E:\\Pictures\\Camera Roll" +
"\\1.jpg");
FileOutputStream os = new FileOutputStream("src/3.jpg");
){
byte[] picture = new byte[1024];// 一次读取1024个字节即1KB
int len;
while ((len = is.read(picture)) != -1) {
os.write(picture, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//将原始的字节输入输出流包装成字节缓冲流后拷贝数据的方法
public class Test1 {
public static void main(String[] args){
try (
FileInputStream is = new FileInputStream("E:\\Pictures\\Camera Roll" +
"\\1.jpg");
//包装成字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(is);
FileOutputStream os = new FileOutputStream("src/3.jpg");
//包装成字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(os);
//BufferedOutputStream bos = new BufferedOutputStream(os,1024 * 16);
//允许指定缓冲区大小,默认为8192,即8KB,上面自定义为16KB
){
byte[] picture = new byte[1024];
int len;
//使用字节缓冲流对象代替原始字节流对象
while ((len = bis.read(picture)) != -1) {
bos.write(picture, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
包装字符输入流,继承了所有字符输入流的方法,自带8K(8192)的字符缓冲池,可以提高字符输入流读取字符数据的性能。
同字节缓冲输入流
构造器 | 说明 |
---|---|
public BufferedReader( Reader r ) | 把低级的字符输入流包装成一个高级的缓冲字符输入流,入参为字符输入流对象,继承了所有字符输入流的方法 |
方法 | 说明 |
---|---|
public String readLine( ) | 每次读取一行数据返回,如果没有数据可读了,会返回null |
public class Test3 {
public static void main(String[] args) {
try (
Reader re = new FileReader("src/a.txt");
BufferedReader br = new BufferedReader(re)
){
String line;
//一次读一行
while ((line = br.readLine()) != null){
System.out.println(line);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
包装字符输出流,继承了所有字符输出流的方法,自带8K的字符缓冲池,可以提高字符输出流向磁盘写字符数据的性能。虽然原始的字符输出流也自带了缓冲池,但是达不到8k的大小且不能自定义
同字节缓冲输出流
构造器 | 说明 |
---|---|
public BufferedWriter( Writer r ) | 把低级的字符输出流包装成一个高级的缓冲字符输出流,入参为字符输出流对象,继承了所有字符输出流的方法 |
方法 | 说明 |
---|---|
public void newLine( ) | 换行写入 |
public class Test2 {
public static void main(String[] args) {
try (
FileWriter fw = new FileWriter("src/b.txt");
BufferedWriter bf = new BufferedWriter(fw)
) {
bf.write("Hello World");
bf.newLine();// 换行
bf.write("Hello World");
bf.write("ddd");
}catch (Exception e) {
e.printStackTrace();
}
}
}
需求:把《出师表》的文章顺序进行恢复到一个新文件中。
分析:
3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必能裨补阙漏,有所广益。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
4.将军向宠,性行淑均,晓畅军事,试用于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
9.今当远离,临表涕零,不知所言。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐托付不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
public class Test3 {
public static void main(String[] args) {
try (
BufferedReader br = new BufferedReader(new FileReader("src/c.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("src/d.txt"))
) {
TreeSet<String> tree = new TreeSet<>();
String line;
while ((line = br.readLine()) != null) {
tree.add(line);
}
for (String s : tree) {
bw.write(s);
bw.newLine();
}
System.out.println("拷贝成功");
}catch (Exception e) {
e.printStackTrace();
}
}
}
分别使用原始的字节流,以及字节缓冲流复制一个很大视频。
public class Test4 {
private static final String COPY_PATH = "E:/TASHISHUI/长风渡/1.mp4";
private static final String FINAL_PATH1 = "E:/TASHISHUI/长风渡/2.mp4";
private static final String FINAL_PATH2 = "E:/TASHISHUI/长风渡/3.mp4";
private static final String FINAL_PATH3 = "E:/TASHISHUI/长风渡/4.mp4";
private static final String FINAL_PATH4 = "E:/TASHISHUI/长风渡/5.mp4";
public static void main(String[] args) {
//文件大小为1.5G
//copy1();//特别慢,根本无法接受,淘汰
copy2();//使用低级的字节流按照字节数组的形式复制文件耗时:6秒
copy3();//使用字节缓冲流按照一个一个字节的形式复制文件耗时:4秒
copy4();//使用字节缓冲流按照字节数组的形式复制文件耗时:1秒
copy5();//使用低级的字节流按照字节数组的形式复制文件并更改数组大小为8kb耗时:1秒
}
public static void copy1() {
long start = System.currentTimeMillis();
try (
FileInputStream is = new FileInputStream(COPY_PATH);
FileOutputStream os = new FileOutputStream(FINAL_PATH1);
){
int temp;
while ((temp = is.read()) != -1) {
os.write(temp);
}
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("使用低级的字节流按照一个一个字节的形式复制文件耗时:"
+ (end - start)/1000 + "秒");
}
public static void copy2(){
long start = System.currentTimeMillis();
try (
FileInputStream is = new FileInputStream(COPY_PATH);
FileOutputStream os = new FileOutputStream(FINAL_PATH2);
){
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("使用低级的字节流按照字节数组的形式复制文件耗时:"
+ (end - start)/1000 + "秒");
}
public static void copy3(){
long start = System.currentTimeMillis();
try (
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(COPY_PATH));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(FINAL_PATH3));
){
int temp;
while ((temp = bis.read( )) != -1) {
bos.write(temp);
}
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("使用字节缓冲流按照一个一个字节的形式复制文件耗时:"
+ (end - start)/1000 + "秒");
}
public static void copy4(){
long start = System.currentTimeMillis();
try (
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(COPY_PATH));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(FINAL_PATH4));
){
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("使用字节缓冲流按照字节数组的形式复制文件耗时:"
+ (end - start)/1000 + "秒");
}
public static void copy5(){
long start = System.currentTimeMillis();
try (
FileInputStream is = new FileInputStream(COPY_PATH);
FileOutputStream os = new FileOutputStream(FINAL_PATH4);
){
byte[] buffer = new byte[8192];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("使用低级的字节流按照字节数组的形式复制文件" +
+ "并更改数组大小为8kb耗时:" + (end - start)/1000 + "秒");
}
}
如果代码编码和被读取的文本文件的编码是一致的,使用字符流读取文本文件时不会出现乱码!
如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件时就会出现乱码!
public class Test1 {
public static void main(String[] args) {
//a.txt与b.txt文件内容相同,但是编码不同
readSame();//txt文件使用UTF8编码,读取时使用UTF8编码
/*
使用UTF8编码
ab我efd
dwa单d
dbrdb
drgs
*/
readDif();//txt文件使用GBK编码,读取时使用UTF8编码
/*
ʹ��GBK����
ab��efd
dwa��d
dbrdb
drgs
*/
}
public static void readSame() {
try (
Reader fr = new FileReader("src/a.txt");
BufferedReader br = new BufferedReader(fr)
) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}catch (Exception e) {
e.printStackTrace();
}
}
public static void readDif(){
try (
Reader fr = new FileReader("src/b.txt");
BufferedReader br = new BufferedReader(fr)
) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
构造器 | 说明 |
---|---|
public InputStreamReader( InputStream is ) | 把传入的原始的字节输入流,按照代码默认编码转成字符输入流(与直接用FileReader的效果一样) |
public InputStreamReader( Inputstream is , String charset ) | 把传入的原始的字节输入流,按照指定字符集编码转成字符输入流**(经常使用)** |
public class Test2 {
public static void main(String[] args) {
//默认使用UTF8编码,b.txt使用GBK编码
try (
//获取原始字节流
InputStream is = new FileInputStream("src/b.txt");
//将原始字节流转换为字符流,编码为GBK
InputStreamReader isr = new InputStreamReader(is, "GBK");
//将字符流包装为缓冲流
BufferedReader br = new BufferedReader(isr);
) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
/*
使用GBK编码
ab我efd
dwa单d
dbrdb
drgs
*/
7.3.1 问题引入
如何控制写出的字符使用指定的字符集编码?
String data = "我爱你中国abd";
byte[] bytes = data.getBytes("GBK")
7.3.2 作用
7.3.2 构造器
构造器 | 说明 |
---|---|
public OutputstreamWriter( OutputStream os ) | 可以把原始的字节输出流,按照代码默认编码转换成字符输出流。 |
public OutputStreamWriter( OutputStream os , String charset ) | 可以把原始的字节输出流,按照指定编码转换成字符输出流**(经常使用)** |
public class Test3 {
public static void main(String[] args) {
try (
OutputStream os = new FileOutputStream("src/e.txt");
OutputStreamWriter osw = new OutputStreamWriter(os, "GBK");
BufferedWriter bw = new BufferedWriter(osw);
) {
bw.write("我是中国人");
bw.newLine();
bw.write("我爱中国");
}catch (Exception e) {
e.printStackTrace();
}
}
}
作用:打印流可以实现更方便、更高效的打印数据出去
构造器 | 说明 |
---|---|
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 ) | 打印任意类型的数据出去,并自动换行 |
public void write( int/byte[ ]/byte[ ]中的一部分 ) | 只支持写字节数据出去 |
public class Test1 {
public static void main(String[] args) {
try (
PrintStream ps = new PrintStream("src/f.txt", Charset.forName("GBK"))
) {
ps.println("普通字符串");
ps.println(23);
ps.write(88);
//ps.write("d");//会报错,因为无法写入字符
}catch (Exception e) {
e.printStackTrace();
}
}
}
/*
普通字符串
23
X
*/
构造器 | 说明 |
---|---|
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) | 打印任意类型的数据出去,并自动换行 |
public void write(int/String/char[ ]/…) | 可以支持写字符数据出去 |
public class Test1 {
public static void main(String[] args) {
try (
PrintWriter pw = new PrintWriter("src/f.txt", Charset.forName("GBK"))
) {
pw.println("普通字符串");
pw.println(23);
pw.write(88);//88的ASCII码为X
pw.write('\n');
pw.write("d");//不会报错,因为PrintWriter的write方法允许写入字符
}catch (Exception e) {
e.printStackTrace();
}
}
}
/*
普通字符串
23
X
d
*/
补充:在原有内容的基础上追加数据
public class Test1 {
public static void main(String[] args) {
try (
//需要使用低级流来指定追加,高级流不允许直接追加
PrintWriter pw = new PrintWriter(new FileWriter("src/f.txt",true))
) {
pw.println("新增");
pw.println(23);
pw.println('X');
}catch (Exception e) {
e.printStackTrace();
}
}
}
/*
普通字符串
23
X
d新增
23
X
*/
将输出到控制台的内容输出到文件中去
public class Test2 {
public static void main(String[] args) {
System.out.println("Hello World!");
System.out.println("sda");
try (
PrintStream pw = new PrintStream("src/1.txt")
) {
// 重定向输出流, 将输出流重定向到文件中
System.setOut(pw);
System.out.println("dasda");
System.out.println("grng");
}catch (Exception e) {
e.printStackTrace();
}
}
}
将数据与数据类型一起写入到指定文件中,但是并不是给我们看的,只有使用DataInputStream才能看到写入的实际内容
构造器 | 说明 |
---|---|
public DataOutputstream( OutputStream out ) | 创建数据输出流包装传入的基础的字节输出流 |
方法 | 说明 |
---|---|
public final void writeByte( int v ) | 将byte类型的数据写入基础字节流对应的文件 |
public final void writeInt( int v ) | 将int类型的数据写入基础字节流对应的文件 |
public final void writeDouble( Double v ) | 将double类型的数据写入基础字节流对应的文件 |
public final void writeUTF( String str ) | 将字符串数据以UTF-8编码成字节写入基础字节流对应的文件 |
public void write(int/byte[ ]/byte[ ]的一部分) | 将字节数据写入基础字节流对应的文件 |
public class Test1 {
public static void main(String[] args) {
try (DataOutputStream dos =
new DataOutputStream(new FileOutputStream("src/1.txt")))
{
dos.writeInt(10);
dos.writeInt(-10);
dos.writeLong(10L);
dos.writeDouble(10.5);
dos.writeUTF("中国");
dos.writeChar('中');
dos.writeBoolean(true);
dos.writeByte(0x41);// A
dos.writeShort(0x3a);// 58
dos.writeChar('A');
dos.writeFloat(10.5f);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
必须使用数据输入流来读取
读取数据输出流写入的数据
构造器 | 说明 |
---|---|
public DataInputStream(InputStream is) | 创建数据输入流包装传入的基础的字节输入流 |
方法 | 说明 |
---|---|
Public final byte readByte( ) | 读取字节数据并返回 |
public final int readInt( ) | 读取int类型的数据并返回 |
public final double readDouble( ) | 读取double类型的数据并返回 |
public final String readUTF( ) | 读取字符串类型数据(UTF8)并返回 |
public int readInt( )/read(byte[ ]) | 读取字节数据 |
public class Test1 {
public static void main(String[] args) {
try (DataInputStream dis =
new DataInputStream(new FileInputStream("src/1.txt")))
{
System.out.println(dis.readInt());
System.out.println(dis.readInt());
System.out.println(dis.readLong());
System.out.println(dis.readDouble());
System.out.println(dis.readUTF());
System.out.println(dis.readChar());
System.out.println(dis.readBoolean());
System.out.println(dis.readByte());// A
System.out.println(dis.readShort());// 58
System.out.println(dis.readChar());
System.out.println(dis.readFloat());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/*
10
-10
10
10.5
中国
中
true
65
58
A
10.5
*/
对象序列化:把Java对象写入到文件中去
对象反序列化:把文件里的Java对象读出来
可以把Java对象进行序列化:把]ava对象存入到文件中去。
构造器 | 方法 |
---|---|
public objectoutputstream( Outputstream out ) | 创建对象字节输出流,包装基础的字节输出流 |
方法 | 说明 |
---|---|
public final void writeobject( object o ) | 将对象写入文件中 |
注意事项
//想要被序列化必须实现序列化接口
public class Student implements Serializable {
private String name;
private int age;
private transient Double score;//使用transient关键字修饰的属性不会被序列化
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 +
'}';
}
}
public class Test1 {
public static void main(String[] args) {
try (
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("src/2.txt"))
){
Student s1 = new Student("张三", 18, 99.9);
oos.writeObject(s1);
System.out.println("序列化成功");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
可以把]ava对象进行反序列化:把存储在文件中的]ava对象读入到内存中来。
构造器 | 说明 |
---|---|
public objectInputstream( InputStream is ) | 创建对象字节输入流,包装基础的字节输入流 |
方法 | 说明 |
---|---|
public final object readObject( ) | 读取对象字节输出流写到文件中的对象 |
public class Test2 {
public static void main(String[] args) {
try (
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("src/2.txt"))
){
Student s1 = (Student) ois.readObject();
System.out.println(s1);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//Student{name='张三', age=18, score=null} score没有被序列化
一次序列化多个对象
用一个ArrayList集合存储多个对象,然后直接对集合进行序列化即可
ArrayList集合已经实现了序列化接口
public class Test3 {
public static void main(String[] args) {
try (
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("src/2.txt"))
){
List<Student> students = new ArrayList<>();
Student s1 = new Student("张三", 18, 99.9);
Student s2 = new Student("李四", 19, 98.9);
Student s3 = new Student("王五", 20, 97.9);
students.add(s1);
students.add(s2);
students.add(s3);
oos.writeObject(students);
System.out.println("序列化成功");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class Test4 {
public static void main(String[] args) {
try (
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("src/2.txt"))
){
List<Student> s1 = (List)ois.readObject();
System.out.println(s1);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//[Student{name='张三', age=18, score=null},
// Student{name='李四', age=19, score=null},
// Student{name='王五', age=20, score=null}]
封装了JAVA提供的对文件、数据进行操作的代码,对外提供了更简单的方式来对文件进行操作,对数据进行读写等。
Commons-io是apache开源基金组织提供的一组有关IO操作的小框架,目的是提高1O流的开发效率。
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) | 写数据 |
IOUtils类提供的部分方法 | 说明 |
---|---|
public static int copy( Inputstream inputstream,Outputstream outputstream ) | 字节流复制文件 |
public static int copy( Reader reader ,Writer writer ) | 字符流复制文件 |
public static void write(String data, OutputStream output, String charsetName) | 写数据 |
(1)集合框架到项目中
(2)代码实例
public class test1 {
public static void main(String[] args) throws IOException {
// 复制文件,从a.txt到b.txt
FileUtils.copyFile(new File("E:/A/a.txt"),new File("E:/A/b.txt"));
// 复制文件夹,从A到B
FileUtils.copyDirectory(new File("E:/A"),new File("E:/B"));
//删除文件夹,无论文件夹是否为空
FileUtils.deleteDirectory(new File("E:/B"));
//向文件中写入数据
FileUtils.writeStringToFile(new File("E:/A/a.txt"),"你好","UTF-8",true);
//读取文件中数据
String msg = FileUtils.readFileToString(new File("E:/A/a.txt"),"UTF-8");
System.out.println(msg);
}
}
public class Test2 {
public static void main(String[] args) throws Exception {
//字节流复制文件
IOUtils.copy(new FileInputStream("E:/A/a.txt"),new FileOutputStream("E:/A/b.txt"));
//字符流复制文件
IOUtils.copy(new FileReader("E:/A/a.txt"),new FileWriter("E:/A/b.txt"));
//向文件中写入数据
IOUtils.write("HHHHH",new FileOutputStream("E:/A/a.txt"),"UTF-8");
}
}