I/O流复习
概念
作用:实现两个设备之间数据的通信
怎么区分要选择的是输入还是输出流
根据内存来看,如果要把数据读入内存里,就是输入流,要把数据从内存写出,就是输出流
分类
- 根据 操作的方式:输入流和输出流
- 根据数据的类型:字节流和字符流
- 字节流(stream):传输的是字节,可以操作任意类型的数据
- 字符流(reader、writer)(只能传输文本):传输的是字节,不同点是在传输过程中加入了编码的操作,让我们的操作更方便
- NIO
基础用法
字符流
public class Demo1 {
public static void main(String[] args) throws IOException {
FileReader reader=new FileReader("d:\\a.txt");//字符流读文件
FileWriter writer=new FileWriter("d:\\b.txt");//字符流写文件
int len;
char[] buf=new char[10];//类似缓冲区
try {
while((len=reader.read(buf))!=-1){//普通的fileReader没有readLine
writer.write(buf,0,len);
writer.flush();//将缓冲区的数据写出去
}
}catch (IOException e){
e.printStackTrace();
}finally {
writer.close();
reader.close();
}
}
}
字节流
public class Demo2 {
public static void main(String[] args) throws IOException {
//1.创建字节输入流
FileInputStream fileInputStream = new FileInputStream("D:\\i.jpg");
//2.创建字节输出流
FileOutputStream fileOutputStream = new FileOutputStream("D:\\j.jpg");
//3.进行读写
int num = 0;
//4.手动开一个缓冲区
byte[] buf=new byte[1024];
try {
while ((num = fileInputStream.read(buf)) != -1) {
fileOutputStream.write(buf,0,num);
}
}catch (IOException e){
e.printStackTrace();
}finally {
//关闭流对象
fileInputStream.close();
fileOutputStream.close();
}
}
}
缓冲流(默认缓冲区间大小8192字节)
-
字符缓冲流
//将A文件的内容字母全部转大写写回A文件中 public class Demo3 { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new FileReader("D:\\a.txt")); String result ; List<String> strings=new ArrayList<>(); while ((result=reader.readLine())!=null){ result=result.toUpperCase(); strings.add(result); } //会之间新建一个a.txt覆盖原文件,所以之前先把全部内容存下来 BufferedWriter writer = new BufferedWriter(new FileWriter("D:\\a.txt")); for(String s:strings){ writer.write(s); writer.newLine();//适应各种操作系统,新增一行 writer.flush(); } writer.close(); reader.close(); } }
-
字节缓冲流
默认缓冲区大小private static int DEFAULT_BUFFER_SIZE = 8192; 8k
public class Demo4 { public static void main(String[] args) throws IOException { //1.创建字节输入流 FileInputStream fileInputStream = new FileInputStream("D:\\i.jpg"); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); //2.创建字节输出流 FileOutputStream fileOutputStream = new FileOutputStream("D:\\j.jpg"); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); //3.进行读写 int num = 0; try { while ((num = bufferedInputStream.read()) != -1) { bufferedOutputStream.write(num); } }catch (IOException e){ e.printStackTrace(); }finally { //关闭流对象 fileInputStream.close(); fileOutputStream.close(); } } }
常用流
标准输入流
public class Demo5 {
public static void main(String[] args) throws IOException {
InputStream inputStream = System.in;
/*
* 实例:实现从键盘不断接收字符的程序
* 要求:一行一行的接收
*/
myReadLine(inputStream);
}
public static void myReadLine(InputStream inputStream) throws IOException {
StringBuffer stringBuffer = new StringBuffer();
while (true) {
int num = inputStream.read();
if (num == '\r') {
continue;
}else if (num == '\n') {
System.out.println(stringBuffer.toString());
//当用户输入over的时候,结束程序
if (stringBuffer.toString().equals("over")) {
break;
}
//将上一次的值清除掉
stringBuffer.delete(0, stringBuffer.length());
}else {
stringBuffer.append((char)num);
}
}
}
}
转换流
public class Demo6 {
public static void main(String[] args) throws IOException {
//1将标准字节输入流转成字符缓冲读入流
BufferedReader bufferedReader
= new BufferedReader(new InputStreamReader(System.in));
//2.将标准字节输出流转成字符缓冲写出流
BufferedWriter bufferedWriter
= new BufferedWriter(new OutputStreamWriter(System.out));
//3.读写
String data = null;
while ((data = bufferedReader.readLine()) != null) {
bufferedWriter.write(data);
bufferedWriter.newLine();
bufferedWriter.flush();
//当输入的内容是over时,结束
if (data.equals("over")) {
break;
}
}
bufferedReader.close();
bufferedWriter.close();
}
}
Properties
public class Demo5 {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
//利用load方法将内容从磁盘读到内存
//注意:使用的文件内容的格式应用是key=value
properties.load(new FileReader("d:\\a.txt"));
properties.list(System.out);
//更改内容
properties.setProperty("a", "hehe");
//写会磁盘 第二个参数是提醒信息
properties.store(new FileWriter("text3.txt"), "hello world");
}
}
序列化
class Person implements Serializable {
//UID作用: 用来区分反序列化时的对象是不是这个类的一个对象(如果这个类在序列化以后有了一定的更改,反序列化时也当成不一样的对象)。如果不是会报InvalidClassException
//UID 有系统自动生成的和自定义两种
//区别:使用自定义的UID,序列化和反序列化时id不会发生改变,所以当反序列化的时候,即使对Person类进行了一些改动,也能继续反序列化
private static final long serialVersionUID = -9061859455350137694L;
String name;
int age;
boolean sex;
public Person(String name, int age, boolean sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
public class Demo6 {
public static void main(String[] args) throws IOException {
ObjectOutputStream oop = null;
try {
oop=new ObjectOutputStream(new FileOutputStream("test.txt"));
oop.writeObject(new Person("赵志阳",23,true));
} catch (IOException e) {
e.printStackTrace();
}
finally {
oop.close();
}
ObjectInputStream objectInputStream=null;
try {
objectInputStream = new ObjectInputStream(new FileInputStream("test.txt"));
Object object = objectInputStream.readObject();
System.out.println(object);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
objectInputStream.close();
}
}
}
File类
public class Demo7 {
public static void main(String[] args) throws IOException {
//创建File类的对象
//第一种方式:直接指定文件的绝对路径
File file1 = new File("D:Demo1.java");
//第二种:通过父路径和子路径的字符串形式
File file2 = new File("D:\\Demo1.java");
//第三种:先得到父路径的对象形式,再跟子路径拼接
File file3 = new File("D:\\");
File file4 = new File(file3,"Demo1.java");
// * 创建文件,在创建时,如果当前的文件已经存在了,不会覆盖
File file5 = new File("D:\\test1.txt");
file5.createNewFile();
// * 创建单层路径,只能创建单层路径,只能创建目录
File file6 = new File("D:\\test2.txt");
//file6.mkdir();
// * 创建多路径,也可创建单层目录,只能创建目录
file6.mkdirs();
// * 判断是否是文件
System.out.println(file6.isFile());//false
// * 判断是否是路径
System.out.println(file6.isDirectory());//true
// * 判断是否隐藏
System.out.println(file6.isHidden());//false
// * 获取最后修改文件的时间
long lastTime = file5.lastModified();
System.out.println(lastTime);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String value = simpleDateFormat.format(new Date(lastTime));
System.out.println(value);
}
}
NIO
buffer缓冲区
public class Demo2 {
public static void main(String[] args) {
/*
* 在创建buffer对象的时候传递的参数就是capacity
* 容量为1024的缓冲区
* 此时buffer的limit和capacity都为1024
* 此时的position是0
*/
ByteBuffer buffer = ByteBuffer.allocate(1024);//开辟容量1024字节
System.out.println("position:"+buffer.position());//0
System.out.println("limit:"+buffer.limit());//1024
/*
* position是5,说明写入了5个字节,position指向的是当前内容的结尾,方便接着往下写
*/
buffer.put("hello".getBytes());
System.out.println(buffer.position());//5
System.out.println(buffer.limit());//1024
//可以继续写
buffer.put("world".getBytes());
System.out.println(buffer.position());//10
//切换为读模式
/*这一步很重要 flip可以理解为模式切换 之前的代码实现的是写入操作
*当调用这个方法后就变成读取操作,那么position和limit的值就要发生变换
*此时capacity为1024不变
*此时limit就移动到原来position所在的位置,相当于把buffer中没有数据的空间
*"封印起来"从而避免读取Buffer数据的时候读到null值
*相当于 limit = position limit = 10
*此时position的值相当于 position = 0
*
*/
buffer.flip();
System.out.println("3:"+buffer.position());//0
System.out.println("3:"+buffer.limit());//10
// //获取单个字节
// //buffer.get();
// //获取多个字节
byte[] data=new byte[buffer.limit()];
buffer.get(data);
System.out.println("data:"+new String(data));
System.out.println("读取data后:"+buffer.position());//从0变成了10,position相当于读字节的指针,内容读完了指到了结尾
System.out.println("读取data后:"+buffer.limit());
//将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素
// buffer.rewind();
// byte[] data1=new byte[buffer.limit()];
// buffer.get(data1);
// System.out.println(new String(data1));
// System.out.println(buffer.position());//从0变成了10,position相当于读字节的指针,内容读完了指到了结尾
// System.out.println(buffer.limit());
/*
* clear():
* API中的意思是清空缓冲区
* 而是将缓冲区中limit和position恢复到初始状态
* 即limit和capacity都为1024 position是0
* 此时可以完成写入模式
*/
buffer.clear();
System.out.println("clear后:"+buffer.position());
System.out.println("clear后:"+buffer.limit());
//可以继续写
buffer.put("temp".getBytes());
//继续读
buffer.flip();
byte[] arr = new byte[buffer.limit()];
buffer.get(arr);
System.out.println("temp:"+new String(arr));
}
}
channel通道
public class Demo7 {
public static void main(String[] args) throws IOException {
//获取文件输入流
FileInputStream fis=new FileInputStream("f:\\all.txt");//16MB大小的文件
//获取文件输出流
FileOutputStream fos=new FileOutputStream("f:\\all2.txt");
//打开通道
FileChannel fisChannel=fis.getChannel();
FileChannel fosChanner=fos.getChannel();
//创建缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
int num;
while ((num=fisChannel.read(buffer))!=-1){
buffer.flip();//使缓冲区数据可读
fosChanner.write(buffer);//写出缓冲区数据
buffer.clear();//清空缓冲区,使其复位到写模式
}
fosChanner.close();
fisChannel.close();
fis.close();
fos.close();
}
}
Path
public class Demo7 {
public static void main(String[] args) throws IOException {
//Path就是用来替代File
//构建Path对象的两种方式
//传一个路径
Path path1 = Paths.get("D:\\123");
//第一个参数是盘符 ,第二个参数是可变参数 下面有多少文件路径就写多少
Path path2 = Paths.get("D:\\", "123","456.txt");
//Path是结合Files工具类使用的
//创建目录
Files.createDirectories(path1);
//判断文件是否存在
if(!Files.exists(path2)) {
//创建文件
Files.createFile(path2);
}
//一次读取文件中所有的行
List<String> readAllLines = Files.readAllLines(Paths.get("src/com/qiangfeng/test/Demo1.java"));
for (String str : readAllLines) {
System.out.println("haha:"+str);
}
//将集合中的内容写入到文件中
Files.write(Paths.get("D:\\", "123","Demo.java"), readAllLines);
}
}
Files
public class Demo8 {
public static void main(String[] args) throws IOException {
/*
* FileVisitor参数代表的是一个文件访问器,walkFileTree()方法会自动遍历
* start路径下的所有文件和子目录,遍历文件和子目录都会触发FileVisitor中相应
* 的方法
* FileVisitResult postVisitDirectory(T dir, IOException exc)
访问子目录之后会触发这个方法
FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
访问子目录之前会触发这个方法
FileVisitResult visitFile(T file, BasicFileAttributes attrs)
访问file文件时触发该方法
FileVisitResult visitFileFailed(T file, IOException exc)
访问file文件失败时触发该方法
返回FileVisitResult是一个枚举
CONTINUE 代表继续访问的后续行为
SKIP_SIBLINGS 代表继续访问的后续行为,但不访问该文件后目录的兄弟文件或目录
SKIP_SUBTREE 代表继续访问的后续行为,但不访问该文件或目录的子目录树
TERMINATE 代表终止访问的后续行为
实际开发中没有必要4个方法都要重写,可以通过FileVisitor的子类SimpleFileVisitor(适配器)来
创建自己的文件访问器,选择性的重写方法
*/
//遍历文件
Files.walkFileTree(Paths.get("D:\\workspace\\BigDataNIO"), new SimpleFileVisitor<Path>() {
//访问文件时触发该方法
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("正在访问"+file+"文件");
// if(file.endsWith("MergeSort.java")) {
// System.out.println("--找到了文件--");
// return FileVisitResult.TERMINATE;
// }
return FileVisitResult.CONTINUE;
}
//开始访问目录时触发的方法
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
System.out.println("正在访问"+dir+"路径");
return FileVisitResult.CONTINUE;
}
});
}
}