目录
FileInputStream和FileOutputStream
ObjectInputStream/ObjectOutputStream
InputStreamReader/OutputStreamWriter
一、IO框架
IO(Input/Output)是计算机输入/输出的接口。Java的核心库java.io提供了全方面的IO接口,包括:文件系统的操作,文件读写,标准设备输出等等
二、File类
一个File类的对象,表示了磁盘上的文件或目录。
File类提供了与平台无关的方法来对磁盘上的文件或目录进行操作。
File类直接处理文件和文件系统。比如删除文件,获取文件长度大小等信息。
File类没有提供方法从文件读取或向文件存储信息。(不能读写文件)
构造方法:
Flle(String directoryPath)
Flle(String directoryPath, String flename)
File(File dirObj, String flename)
File定义了获取File对象标准属性的方法
部分File类常用方法:
public String getName()
public String getParent()
public Flle getParentFile()
public String getAbsolutePath()
public boolean exists()
public File[] listFiles()
publc boolean IsDirectory()
public boolean isFile()
public long length()
boolean delete()
boolean mkdir()
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) {
File file = new File("D:\\练习\\java");
/*返回绝对路径*/
System.out.println(file.getAbsoluteFile());
/*文件的长度;如果打开的是文件夹或目录,返回文件夹或目录本身自己所占的磁盘空间(并不是文件夹中的所有文件大小),一般是一个扇区的大小,一般是512字节,也就是一簇,一簇就是4096*/
System.out.println(file.length());
/*是否为文件*/
System.out.println(file.isFile());
/*是否为目录*/
System.out.println(file.isDirectory());
/*测试文件名/目录是否存在*/
System.out.println(file.exists());
/*返回文件的父目录*/
System.out.println(file.getParent());
/*删除文件,为文件夹,文件夹为空才可以删除*/
System.out.println(file.delete());
System.out.println("-------------------------");
/*遍历目录*/
String[] files = file.list();
for (String f: files) {
System.out.print(f+"\t\t");
}
System.out.println();
/*指定条件查找*/
String[] files1 = file.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".gif");/*条件*/
}
});
for (String f: files1) {
System.out.print(f+"\t\t");
}
System.out.println();
System.out.println("-------------------------");
File file1 = new File("D:\\练习\\Python");
/*创建文件夹*/
System.out.println(file1.mkdir());
File file2 = new File("D:\\练习\\Python\\lianxi.txt");
/*创建文件*/
try {
System.out.println(file2.createNewFile());
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、递归算法
递归算法
程序调用自身的编程技巧称为递归(recursion)。
一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归算法注意
递归就是在过程或函数里调用自身。在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。
阶乘
public class FactorialDemo {
public static void main(String[] args) {
System.out.println(FacUtil.getFac(5));
}
}
class FacUtil{
/*求阶乘*/
public static int getFac(int number){
if (number == 1) {
return 1;
}
/*
5!= 5 * 4!--->number * getFac(4)-->getFac(number - 1)
5*4! 4*3! 3*2! 2*1! 结束----》 1*0!
* */
return number * getFac(number - 1);
}
}
四、流的概念及分类
流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样。
流的分类
流按其流向分为“输入流"和“输出流”
流按数据传输单位分为“字节流"和“字符流”
“字节流"用来读写8位二进制的字节。
“字符流"用来读写16位二进制字符。
流按功能分为“节点流"和“过滤流”
“节点流”用于直接操作目标设备的流。例如:磁盘或一块内存区域。
“过滤流”是对一个已存在的流的链接和封装,通过对数据进行处理
为程序提供功能强大、灵活的读写功能。
import java.io.File;
import java.util.ArrayList;
/*
*需求:给定一个目录,按照层次来显示目录结构,文件名后加*;文件夹后加\\来表示;要求先显示目录,在显示文件
*
* 解题思路:
*1、File类里面的ListFile来遍历文件夹
*2、使用list集合
* 3、递归算法
* */
public class IteratorDirDemo {
public static void main(String[] args) {
IteratorUtil.iteratorDir(new File("D:\\练习"));
}
}
class IteratorUtil{
private static int level = 0;/*层级数*/
/*迭代目录*/
public static void iteratorDir(File file){
if (file != null) {
/*递归的出口;是文件或文件夹就返回*/
if (file.isFile()|| file.listFiles().length==0) {
return;
}else{
/*遍历,未排序*/
File[] files = file.listFiles();
/*排完序的数组*/
files = sort(files);
for (File f:files){
StringBuilder stringBuilder = new StringBuilder();
if (f.isFile()) {
/*追加制表符*/
stringBuilder.append(getTab(level));
stringBuilder.append(f.getName());
stringBuilder.append("*");
}else{
stringBuilder.append(getTab(level));
stringBuilder.append(f.getName());
stringBuilder.append("\\");
}
System.out.println(stringBuilder.toString());
if(f.isDirectory()){
level++;/*进入目录遍历,层数+1*/
iteratorDir(f);/*递归调用遍历目录的方法*/
level--;/*目录数=1,层数-1*/
}
}
}
}
}
private static File[] sort(File[] files){
ArrayList<File> files1 = new ArrayList<>();
/*先存文件夹*/
for (File f:files) {
if (f.isDirectory()) {
files1.add(f);
}
}
/*在存文件*/
for (File f:files) {
if (f.isFile()) {
files1.add(f);
}
}
/*把集合中的元素转换成指定大小和类型的数组*/
return files1.toArray(new File[files1.size()]);
}
/*根据level数来获取\t层数*/
private static String getTab(int level){
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < level; i++) {
stringBuilder.append("\t");
}
return stringBuilder.toString();
}
}
五、InputStream抽象类
字节流类用于向字节流读写8位二进制的字节。一般地,字节流类主要用于读写诸如图象或声音等的二进制数据。
字节流类以InputStream和OutputStream为顶层类。它们都是抽象类。
InputStream是定义了字节输入流的抽象类
InputStream中定义的方法
public abstract Int read()
public int read(byte[] b)
public int read(byte[] b, int off, Int len)
public long skip(long n)
public Int avallable()
public vold close()
六、OutputStream抽象类
OutputStream是定义了字节输出流的抽象类
该类所有方法返回void值,在出错情况下抛lOException异常
OutputStream中定义的方法
public abstract vold write(int b)
public vold write(byte[] b)
public vold write(byte[] b, Int off, Int len)
public vold flush()
public vold close()
FileInputStream和FileOutputStream
每个抽象类都有多个具体的子类,这些子类对不同的外设进行处理,例如磁盘文件,网络连接,甚至是内存缓冲区。
FileInputStream类表示能从文件读取字节的InputStream类
常用的构造方法:
FilelnputStream(String filepath)
FilelnputStream(File fleObj)
FileOutputStream类表示能向文件写入字节的OutputStream类
构造方法:
FileOutputStream(String filePath)
FileOutputStream(File fileObj)
FileOutputStream(Sting filePath, boolean append)
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileInputStreamAndFileOutputStream {
public static void main(String[] args) throws Exception {
File src = new File("D:\\练习\\java\\jdk api 1.8_google.CHM");
File data = new File("D:\\练习\\java\\Java_API_1.8.CHM");
CopyFiles.copyFile(src,data);
}
}
class CopyFiles{
/**
*src-->被拷贝出来的文件
* data-->拷贝出来文件
* */
public static void copyFile(File src,File data) throws Exception {
FileInputStream fileInputStream = new FileInputStream(src);
FileOutputStream fileOutputStream = new FileOutputStream(data);
long time1 = System.currentTimeMillis();
byte[] bytes = new byte[1024 * 1024];/*创建一个缓冲区1M*/
int len = 0;
while ((len = fileInputStream.read(bytes)) != -1){
fileOutputStream.write(bytes,0,len);
}
fileInputStream.close();
fileOutputStream.close();
long time2 = System.currentTimeMillis();
System.out.println("花费时间为:"+(time2 - time1) +"毫秒");
}
}
ByteArrayInput/OutputStream
ByteArrayInputStream是把字节数组当成源的输入流
两个构造方法,每个都需要一个字节数组提供数据源:
ByteArayInputStream(byte array[])
ByteArayInputStream(byte array[], int start, int numBytes)
ByteArrayOutputStream是把字节数组当作目标的输出流
有两个构造方法:
ByteArrayOutputStream( )
创建一个新的byte数组输出流
ByteArrayOutputStream(int numBytes)
创建一个新的byte数组输出流,具有指定大小缓冲区(字节为单位)
import java.io.*;
public class ByteArrayStreamDemo {
public static void main(String[] args) throws IOException {
String str = "hello word";
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(str.getBytes());
int data = -1;
while((data = byteArrayInputStream.read())!= -1){
System.out.print((char) data);
}
/*ByteArrayInputStream并未调用系统本地资源,所以无需关闭*/
System.out.println();
byteArrayInputStream.close();
System.out.println("----------------------------");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.write(97);
byteArrayOutputStream.write(65);
byteArrayOutputStream.write("hello word".getBytes());
byte[] bytes = byteArrayOutputStream.toByteArray();
for (byte data1 : bytes){
System.out.print((char) data1);
}
FileOutputStream fileOutputStream = new FileOutputStream("D:\\练习\\java\\aaa.txt");
byteArrayOutputStream.writeTo(fileOutputStream);
fileOutputStream.close();
}
}
七、过滤流
过滤流(filtered stream)仅仅是为底层透明地提供扩展功能的输入流(输出流)的包装。这些流一般由普通类的方法(即过滤流的一个父类)访问。
过滤字节流FilterInputStream和FilterOutputStream。构造方法:
FilterOutputStream(OutputStream os)
FlilterInputStream(InputStroam ls)
这些类提供的方法和InputStream及OutputStream类的方法相同
常用的BufferedInputStream和BufferedOutputStream,DatalnputStream和DataOutputSteam就是一个字节过滤流。 DatalnputStream与DataOutputStream
数据输入输出流允许应用程序读写基本Java数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取。读写顺序要保持一致。
import java.io.*;
public class BufferedInputAndBufferedOutput {
public static void main(String[] args) throws Exception {
File src = new File("D:\\练习\\java\\jdk api 1.8_google.CHM");
File data = new File("D:\\练习\\java\\Java_API_1.8.CHM");
CopyFiles.copyFile(src,data);
}
}
class Copy{
/**
*src-->被拷贝出来的文件
* data-->拷贝出来文件
* */
public static void copyFile(File src,File data) throws Exception {
FileInputStream fileInputStream = new FileInputStream(src);
FileOutputStream fileOutputStream = new FileOutputStream(data);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
long time1 = System.currentTimeMillis();
int len = 0;
while ((len = bufferedInputStream.read()) != -1){
bufferedOutputStream.write(len);
}
bufferedInputStream.close();
bufferedOutputStream.close();
long time2 = System.currentTimeMillis();
System.out.println("花费时间为:"+(time2 - time1) +"毫秒");
}
}
import java.io.*;
public class DataInputStreamAndDataOutputStreamDemo {
public static void main(String[] args) throws IOException {
String name = "张三";
int age = 20;
char sex = '男';
boolean flag = true;
double money = 999.999;
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("D:\\练习\\java\\bbb.txt"));
dataOutputStream.writeUTF(name);
dataOutputStream.writeInt(age);
dataOutputStream.writeChar(sex);
dataOutputStream.writeBoolean(flag);
dataOutputStream.writeDouble(money);
dataOutputStream.close();
DataInputStream dataInputStream = new DataInputStream(new FileInputStream("D:\\练习\\java\\bbb.txt"));
/*读的顺序和写的顺序一致*/
System.out.println(dataInputStream.readUTF());
System.out.println(dataInputStream.readInt());
System.out.println(dataInputStream.readChar());
System.out.println(dataInputStream.readBoolean());
System.out.println(dataInputStream.readDouble());
dataInputStream.close();
}
}
八、字符流
Reader和Writer抽象类
字节流提供处理任何类型输入/输出操作的足够功能,但不能直接操作Unicode字符,因而需要字符流
字符流层次结构的项层是Reader和Writer抽象类
Reader是定义Java的流式字符输入模式的抽象类
Reader抽象类中的方法:
public Int read(CharBuffer target) throws IOException
public Int read()
......
Writer是定义流式字符输出的抽象类
该类的方法都返回void值并在出错条件下抛IOException异常
Writer抽象类中方法:
public vold write(int c)
public vold wite(char[] cbuf)
FileReader和FileWriter
FileReader类表示可以读取文件内容的Reader类
构造方法:
FileReader(String filePath)
FileReader(File fileObj)
FileWriter表示可以写文件的Writer类
构造方法:
FileWriter(String filePath)
FileWriter(String filePath, boolean append)
FileWriter(File fileObj)
import java.io.FileReader;
import java.io.FileWriter;
public class FileReaderAndFileWriterDemo {
public static void main(String[] args) throws Exception {
FileReader fileReader = new FileReader("D:\\练习\\java\\bbb.txt");
FileWriter fileWriter = new FileWriter("D:\\练习\\java\\hhh.txt");
char[] chars = new char[100];
int len = 0;
while((len = fileReader.read(chars)) != -1){
fileWriter.write(chars,0,len);
}
fileReader.close();
fileWriter.close();
}
}
BufferedReader和BufferedWriter
BufferedReader通过缓冲输入提高性能
两个构造方法:
BufferedReader(Reader inputStream)
BufferedReader(Reader inputStream, int bufSize)
BufferedWriter通过缓冲输出提高性能
两个构造方法:
BufferedWriter(Writer outputStream)
BufferedWriter(Writer outputStream, int bufSize)
import java.io.*;
public class BufferedReaderAndBufferedWriterDemo {
public static void main(String[] args) throws Exception {
FileReader fileReader = new FileReader("D:\\练习\\java\\bbb.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
FileWriter fileWriter = new FileWriter("D:\\练习\\java\\hhh.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
String len= null;
while ((len = bufferedReader.readLine()) != null){
System.out.println(len);
bufferedWriter.write(len);
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
}
九、其他流
ObjectInputStream/ObjectOutputStream
ObjectlnputStream/ObjectOutputStream
ObjectOutputStream和ObjectlnputStream分别与FileOutputStream和
FileInputStream一起使用时,可以为应用程序提供对对象的持久存储。我们把对象以某种特定的编码格式写入称之为“序列化”。把写入的编码格式内容还原成对象称之为“反序列化”。
被序列化的对象必须实现Serializable接口。
import java.io.*;
public class ObjectInputStreamAndObjectOutputStreamDemo {
public static void main(String[] args) throws Exception {
Student4 student4 = new Student4("张三",20);
/* var objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\练习\\java\\uuu.txt"));
objectOutputStream.writeObject(student4);
objectOutputStream.close();
System.out.println("写入成功");*/
var objectInputStream = new ObjectInputStream(new FileInputStream("D:\\练习\\java\\uuu.txt"));
Student4 o = (Student4) objectInputStream.readObject();
System.out.println(o);
}
}
class Student4 implements Serializable{
private static final long serialVersionUID = -5619739187854979859L;
private String name;
private int age;
private char sex;
public Student4() {
super();
}
public Student4(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Student1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
InputStreamReader/OutputStreamWriter
InputStreamReader,OutputStreamWriter
转换流是指将字节流与字符流之间的转换。
转换流的出现方便了对文件的读写,她在字符流与字节流之间架起了一座桥梁,使原本毫无关联的两种流操作能够进行转化,提高了程序的灵活性。
字节流中的数据都是字符时,转成字符流操作更高效。
如果使用非默认编码保存文件或者读取文件时,需要用到转换流,因为字节流的重载构造方法中有指定编码格式的参数,而FielReader与 FileWriter 是默认编码的文本文件。
import java.io.*;
public class InputStreamReaderWriterDemo {
public static void main(String[] args) throws Exception {
var bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\练习\\java\\uuu.txt"), "utf-8"));
bufferedWriter.write("你好");
bufferedWriter.close();
var bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\练习\\java\\uuu.txt"), "utf-8"));
String line = null;
while ((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
}
}
RandomAccessFile
RandomAccessFile随机访问文件支持对随机访问文件的读取和写入
随机访问文件的行为类似存储在文件系统中的一个大型byte数组。
存在指向该隐含数组的光标或索引,称为文件指针
输入操作从文件指针开始读取字节,随着对字节的读取而前移此文件指针
如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,随着对字节的写入而前移此文件指针
写入隐含数组末尾之后的输出操作导致该数组扩展。
该文件指针可以通过getFilePointer方法读取,通过seek方法设置