IO流基础

I/O流复习

概念

作用:实现两个设备之间数据的通信

怎么区分要选择的是输入还是输出流

根据内存来看,如果要把数据读入内存里,就是输入流,要把数据从内存写出,就是输出流

分类

  1. 根据 操作的方式:输入流和输出流
  2. 根据数据的类型:字节流和字符流
    1. 字节流(stream):传输的是字节,可以操作任意类型的数据
    2. 字符流(reader、writer)(只能传输文本):传输的是字节,不同点是在传输过程中加入了编码的操作,让我们的操作更方便
  3. 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字节)

  1. 字符缓冲流

    //将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();
        }
    }
    
  2. 字节缓冲流

    默认缓冲区大小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;
			}
		   });
		}
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值