File,递归算法,IO流
概述 Java I/O主要包括如下几个层次,包含三个部分:
1.流式部分――IO的主体部分;
2.非流式部分――主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类;
3.其他类--文件读取部分的与安全相关的类,如:SerializablePermission类,以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。
主要的类如下:
1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。
2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。
4.Reader(文件格式操作):抽象类,基于字符的输入操作。
5. Writer(文件格式操作):抽象类,基于字符的输出操作。
6. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。
一、File
一个用来对文件、文件夹(目录)创建、删除、遍历等操作的类
public class BaseTest {
public static void main(String[] args) {
//==================File 四个静态属性==================
//字符串形式的名称分隔符win是\ linux是/
String separator = File.separator;
//字符形式的名称分隔符win是\ linux是/
char separatorChar = File.separatorChar;
//字符串形式的路径分隔符win是; linux是:
String pathSeparator = File.pathSeparator;
//字符形式的路径分隔符win是; linux是:
char pathSeparatorChar = File.pathSeparatorChar;
//=================File 四个构造方法=======================
File file = new File("D"+ File.pathSeparator +File.separator+"jks");
File file1 = new File(file,"test.txt");//相对路径一般是相对于工程下面的文件
File file2 = new File("D:","jsk");
//================file 常用成员方法=======================
//创建文件
boolean newFile = file.createNewFile();
//创建文件夹(mkdirs递归创建)
file.mkdir();//创建一级目录,也就是说只能创建一个文件夹。如果要使用创建多层的目录使用mkdirs
file.mkdirs();
//判断文件夹是否存在
boolean exists = file.exists();
//删除,只能删除空文件夹,
file.delete();
//目录递归遍历
readFile(file);
}
public static void readFile(File file){
//获取当前目录下的所有一级目录的file数组
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
if(files[i].isDirectory()){
readFile(files[i]);//如果是文件夹,继续寻找
}else {
System.out.println(files[i].getPath());
}
}
}
}
该问题的思想是从后往前推。以第几天为变量。
已知第10天桃子是1个。
第一天桃子数是f(n)
第二天桃子数是f(n+1)
两者之间有一个关系是
f(n) - f(n)/2 -1 = f(n+1)
经过换算公式。得到
f(n) = 2(f(n+1) + 1)
因此可以写出递归方法
public static int sum(int n) {
if (n == 1) {
return 1;
}else {
return 2 * sum(n + 1) + 2;
}
}
/**
* 买酒的钱数
* @param money 消费金额
*/
public static void buy(int money){
// 确定能买多少瓶
int buynum = money / 2;
totalNum += buynum;
// 确定剩余多少钱
int allMoney = money - buynum * 2;
// 把盖子和瓶子换算成钱, 统计盖子数和瓶子数
lastCoverNumber += buynum;
lastBottleNumber += buynum;
if (lastCoverNumber >= 4) {
allMoney += lastCoverNumber / 4 * 2;
}
lastCoverNumber = lastCoverNumber % 4;
if (lastBottleNumber >= 2) {
allMoney += lastBottleNumber / 2 * 2;
}
lastBottleNumber %= 2;
if (allMoney >= 2) {
buy(allMoney);
}
}
pathSeparator、separator区别: File.pathSeparator指的是分隔连续多个路径字符串的分隔符,例如: java -cp test.jar;abc.jar HelloWorld 就是指“;”
File.separator才是用来分隔同一个路径字符串中的目录的,例如: C:\Program Files\Common Files 就是指“\”
File对象可以定位文件和文件夹 file封装的对象仅仅是一个路径名,这个路径可以是存在的也可以是不存在的
二、io
1、概述
java中的数据是以流的方式传递,也就是二进制方式传递,有字节和字符流;分为输出输入流两种,出入(写读)都是相对内存而言的,即输出指的是吧数据从内存写到磁盘,输入指的是把数据从磁盘读入内存
2、流体系
使用字节流好还是字符流好? 所有的文件在硬盘或在传输时都是以字节的方式进行的,包括图片等都是按字节的方式存储的,而字符是只有在内存中才会形成,所以在开发中,字节流使用较为广泛。 字节流是最基本的,所有的InputStream和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的。但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化。这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联。 在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的。在从字节流转化为字符流时,实际上就是byte[]转化为String时,public String(byte bytes[], String charsetName) 有一个关键的参数字符集编码,通常我们都省略了,那系统就用操作系统的lang。而在字符流转化为字节流时,实际上是String转化为byte[]时,byte[] String.getBytes(String charsetName)也是一样的道理。至于java.io中还出现了许多其他的流,按主要是为了提高性能和使用方便,如BufferedInputStream,PipedInputStream等。 实际字节流和字符流区别处理代码和以上区别,还有字符流再操作文件的时候加入了缓存区
try {
InputStream inputStream = new FileInputStream("day1/src/aaa.txt");
int b;
while ((b = inputStream.read()) != -1){
System.out.println(b);
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
InputStream inputStream = new FileInputStream("day1/src/aaa.txt");
byte[] b = new byte[3];
int num = inputStream.read(b);//返回值读取了几个字节
System.out.println(num);
String str = new String(b);
System.out.println(str);
int num2 = inputStream.read(b);//读取多少个
String str2 = new String(b, 0, num2);//展示多少个。
使用file.length()方法获取读取文件的大小用来定义字节数组
byte[] b = new byte[(int)file.length()];
这样可以一次性读取文件。
//读取全部字节数组
byte[] buffer = file.readAllBytes();
String(buffer);
代码区分
public static void main(String\[] args) throws IOException {
File file= new File("d:"+File.separator+"test.txt");
String str = "hello world";
//=====================字节流使用=====================
FileOutputStream outputStream = new FileOutputStream(file);
outputStream.write(str.getBytes());//字节流只能操作字节,将数据从内存输出(写入)磁盘
outputStream.close();
//=====================字符流使用=====================
FileWriter writer = new FileWriter(file);
writer.write(str);//字符流直接对字符操作 将数据从内存输出(写入)磁盘
/**关闭之后才会将数据写入,没有这句文件没有内容,因为字符流内容还在缓冲区,
* 只有调用close会强制刷新缓冲区数据进行输出,如果想在不关闭时也可以将
* 字符流的内容全部输出,则可以使用Writer类中的flush()方法完成*/
writer.close();
}
三、字节流 字节流的两个顶层inputStream、 outputStream 都是抽象类,不能直接new,由其子类实现各种文件输出输入 读取,音视频更好 1、字节输入流FileInPutStream
2、字节输出流FileOutPutStream
写入数据完成后需要刷新数据,才能保证正确写入。
OutputStream os = new FileOutputStream(file); //先清空之前的数据。在写入。添加参数append = true的时候。就会在原有数据的基础上添加数据。
os.write("这是我的目的".getBytes());
//刷新输入,将缓存中的内容写入到磁盘中
os.flush();
os.write("这是我的目的".getBytes());
os.write("\r\n".getBytes());
os.write("换行符号\r\n".getBytes());
os.write("这是我的地盘".getBytes());
os.close();//关闭管道,包含了刷新功能。会释放资源。
3、使用字节流对文件复制
File file = new File("day1/src/aaa.txt");
InputStream inputStream = new FileInputStream(file);
byte[] b = new byte[(int) file.length()];
int num = inputStream.read(b);//读取内容到内存,
OutputStream os = new FileOutputStream("day1/src/bbb.txt");//输出内容到磁盘
os.write(b);
os.flush();
四、字符流 字符流的两个顶层父类Reader和Writer都是抽象类,不能直接new。 读取字符串文档使用字符流更好
1、字符输入流
2、字符输出流
备注:flush()和close()区别
flush()将缓冲区的数据刷新到目的地,刷新后流还可以继续使用
close()关闭资源,但在关闭前会将缓冲区的数据先刷先到目的地,然后关闭,关闭之后不可使用,如果写入数据过多,一定要一边写一边刷新 最后一次可以不用刷新,由close完成刷新并关闭
只有writer的子类才使用flush()
注意:
File file = new File("day1/src/aaa.txt");
try(
InputStream inputStream = new FileInputStream(file);
OutputStream os = new FileOutputStream("day1/src/bbb.txt");
) {
byte[] b = new byte[(int) file.length()];
int num = inputStream.read(b);//读取内容到内存,
//输出内容到磁盘
} catch (Exception e) {
throw new RuntimeException(e);
}
3、字符流实现文件的复制
五、转换流
1、字符转字节流类OutPutStreamWriter
OutputStreamWriter(Outputstream in)//给一个字节输出流的子类 FileOutputStream
OutputStreamWriter(Outputstream in ,charset s)//给一个字节输出流的子类,并且指定编码集 如果不给出 默认是gbk
2、字节转字符流类InputStreamReader
InputStreamReader(inputstream out)//给一个字节输入流子类 如FileInputStream
InputStreamReader(inputstream out ,charset s)//给一个字节输入流子类,并且指定编码集 如果不给出 默认是gbk
总结
六、缓冲流
缓冲流是为了提高java中io流的传输效率,有字节缓冲流 字符缓冲流,字节缓冲流本身没有传输流的能力,而是依靠一起流,对其提高效率,
1、字节输出缓冲流BufferedOutputStream
2、字节输入缓冲流BufferedInputStream
3、字符输出缓冲流BufferedReader
4、字符输入缓冲流BufferedWriter
5、字符缓冲流复制文件
七、对象流(序列化流) 如果将一个对象写入到本地文件中,被称为对象的序列化
如果将一个本地文本中的对象读取出来,被称为对象反序列化
1.要实现类的对象的序列化,首先本来要实现implements Serializable
2.一个对象流只能操作一个对象,如果试图采用一个对象流操作多个对象的话,会出现EOFException【文件意外达到了文件末尾】。如果向将多个对象序列化到本地,可以借助于集合,【思路:将多个对象添加到集合中,将集合的对象写入到本地文件中,再次读出来,获取到的仍然是集合对象,遍历集合】
3.对象序列化和反序列化的时候需要注意,序列化的时候有一个
private static final long serialVersionUID = 1L;
其中serialVersionUID的值是一个任意的整数,序列化和反序列化的时候这个数必须一致,否则将不能反序列化。会报错:
java.io.InvalidClassException: demo_0806.Student; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
八、内存流 向内存写数据
ByteArrayInputStream bis = new ByteArrayInputStream(t.getBytes());
读取内存里面的数据
ByteArrayOutputStream bos = new ByteArrayOutputStream();
案列:
String t = "大家好!"; //通过ByteArrayInputStream的构造方法向内存中写入数据 ByteArrayInputStream bis = new ByteArrayInputStream(t.getBytes()); //创建读内存的流 ByteArrayOutputStream bos = new ByteArrayOutputStream(); int temp=0; while((temp=bis.read())!=-1){//注意这里是bis不是bos char c=(char)temp; bos.write(Character.toUpperCase(c));// toUpperCase(c)转成大写 } System.out.print(bos.toString()); bis.close(); bos.close(); 九、打印流printStream 平时我们在控制台打印输出,是调用 print 方法和 println 方法完成的,这两个方法都来自于java.io.PrintStream 类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。
public static void main(String[] args) throws FileNotFoundException { //系统默认流向是控制台 System.out.println("hello"); PrintStream printStream = new PrintStream("d:"+File.separator+"test.txt"); //改变默认流向输出 System.setOut(printStream); System.out.println("hello ..."); }
十、使用总结 1、首先决定要操作的是字符还是字节
字节选择FileInputStream和FileOutPutStream 字符选择FileWriter和FileReader 一般视频 音频 图片用字节 文本用字符 2、其次决定要不要转字符
InputStramReader和OutPutStreamWriter 3、然后决定用不用转换字符提高速率
提高字节输出输入BufferedInputStream和BufferedOutPutStream 提高字符输出输入BufferReader BufferWriter 4、操作对象使用ObjectInputStream和ObjectOutputStream
转载自:https://juejin.cn/post/7241750362738688060