精华内容
下载资源
问答
  • java核心库---IO(1)

    2018-05-14 22:19:31
    java的集合框架:类和接口存在于java.util包中java的IO: 类和接口存在于java.io包中//File类指的是文件/目录File类的介绍和路径分割符:File类是IO包中唯一表示磁盘文件磁盘目录的对象的路径该类包含了创建,删除文件...

    java的集合框架:类和接口存在于java.util包中

    java的IO:          类和接口存在于java.io包中

    //File类指的是文件/目录

    File类的介绍和路径分割符:

    File类是IO包中唯一表示磁盘文件磁盘目录的对象的路径

    该类包含了创建,删除文件,重命名文件,判断文件,读写权限以及文件是否存在,查询等功能方法

    只能设置和获取文件本身的信息,不能设置和获取文件的内容

    在java开发中:

    Unix系统严格区分大小写

    Windows系统不区分大小写

    不同系统路径分割符和属性分隔符不同

    Unix系统:     使用"/"来分割目录路径  使用":"来分割属性

    Window系统: 使用"\"来分割一般路径,但是在java中一个"\"代表转义,在Windows平台的java代码中表示路径,就得使用两个反斜线"\\"来表示,第一个反斜线代表转义,第二个反斜线才代表反斜线的意思,但是,Windows系统也支持"/"来分割路径,使用";"分割属性

    //为了方便,统一使用"/"来分割目录路径

    如果以后不知道在哪个平台上运行,该如何解决编写分隔符的问题?此时File类中提供了两类静态常量,它们可以根据不同的系统,产生系统相对应的分隔符

    //两类常量,每一类的两个常量是等价的
     第一类:路径分隔符
            static String pathSeparator    与系统有关的路径分隔符,为了方便,它被表示为一个字符串。     
            static char pathSeparatorChar  与系统有关的路径分隔符。 
     第二类:属性分割符
            static String separator        与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。 

            static char separatorChar      与系统有关的默认名称分隔符。 

    File类中重写了toString()方法,所以输出File对象则输出的是路径

    源码如下:

    public String toString() {
            return getPath();

        }

    File类中获取文件路径的方法:

         

    // 操作File路径和名称,该文件可以不存在,因为它只代表的是一个路径而已
    File getAbsoluteFile() :获取绝对路径
    String getAbsolutef1ath() :获取绝对路径
    String getPath() :获取文件路径
    String getName() :获取文件名称
    File  getparentFile() :获取上级目录文件
    String getparent() :获取上级目录文件路径

    File类中检测状态的方法:

           boolean canExecute() :判断文件是否是可执行文件
           boolean canRead() :判断该文件是否可读
           boolean canWrite() :判断该文件是否可写
           boolean isHidden() :判断该文件是否为隐藏文件
           long lastModified() :获得该文件的最后修改时间

           long length() :获取该文件的长度大小(单个字符)

    File类中文件操作的方法:

           boolean isFile() :是否是文件
           boolean createNewFile() :创建新的文件
           static File createTempFile(String prefix,String suffix) :创建临时文件
           boolean delete() :删除文件
           void deleteOnExit() :在JVM停止时删除文件

           boolean exists() :判断文件是否存在

    File类中目录操作的方法:

           boolean isDirectory(): 判断是否为目录
           boolean mkdir(): 创建当前目录
           boolean mkdirs(): 创建当前目录和上级目录
           String[] list(): 列出所有文件名
           File[] list(): 列出所有文件对象
           static File[] listRoots(): 列出所有盘符

           boolean renameTo(File dest) :重新修改名称

    IO流的分类和操作模板:

    1.  IO流的分类,站在不同的角度上,分类分类方式是不同的

          1):根据流向划分:输入流和输出流

          2):根据数据的单位划分:字节流和字符流

          3):根据功能划分:节点流和包装流

    2.  IO流的四大基流: 

           字节输入流(InputStream), 字节输出流(OutputStream), 字符输入流(Reader), 字符输出流(Writer)

    注意:

           1).该四大基流均是抽象类,其他流都是继承于这四大基流,所以不能创建四大基流的对象,只能创建其子类对象

           2).无论是什么流,最后都必须用close方法关闭资源(如果操作文件,就得开通一个流对象关联我们的磁盘文件,如果不关闭资源,那么磁盘的文件一直被程序引用着,不能删除,也不能修改)

    3.  操作IO流的模板:

           1).创建源或者目标对象

               以文件流为例:

               输入操作: 把文件中的数据流向程序当中,此时文件是源,程序是目标

               输出操作:把程序中的数据流向到文件中,此时文件是目标,程序是源

           2). 创建IO输入对象

               输入操作: 创建输入流对象

               输出操作: 创建输出流对象

           3). 具体的IO操作

               输入操作: 输入流对象的read方法 

               输出操作: 输出流对象的write方法

           4). 关闭资源(勿忘)

               输入操作: 输入流对象.close()

               输出操作: 输出流对象.close()

    4. FileOutputStream写数据的方法:

           void write(int b);把一个字节写到文件中
           void write(byte[] b);把数组中所有的数据写入文件中

           void write(byte[] b,int off,int len);把数组b中从off索引开始的len个字节写到文件中


    5. FileInputStream读数据的方法:

          //注意:如果读取到最后没有数据的时候,返回值为-1
          1. int read(); 读取一个字节 
          2. int read(byte[] b);读取多个字节,并存储到数组中,从数组索引为0的位置开始存,返回读取了几个字节, 输出的时候一般要用        len, len表示读取的实际的字节数

          方式2比方式1效率高,因为方式1每次才读一个字节,太慢了,方式2每次可以读取很多字节

    6. 文件输出流实现换行和末尾追加

         换行符:

                   针对不同的系统,里面的换行符号是不一样的

                                Windows: \r\n
                                Linux  : \n

                                mac    : \r

         末尾追加的方法:

                    public FileOutputStream(File file,boolean append)
                                                        throws FileNotFoundException

             //布尔值为true则代表末尾追加,一般情况下,就是不写true,系统也会末尾追加 

    7.文件的拷贝

    文件的拷贝需要注意三点:

                     1). 如果该路径的目标文件不存在,则系统会先在该路径下创建这个文件,然后进行文件的拷贝

                     2). 如果打开文本文件,如果出现乱码则使用字节流,否则使用字符流

                     3). 读取一个字节写入一个字节可以解决乱码问题

    实例如下:


    8.文件名称过滤器

    文件名称过滤器的两个高级方法:

              public String[] list(FilenameFilter filter)返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录  

    public File[] listFiles(FilenameFilter filter)返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录

    注释:  文件过滤器的方法参数是一个接口,一般采用匿名内部类的方式实现,要重写该接口的accept方法,当且仅当该名称应该包含在文件列表中时返回 true;否则返回 false。

    实例如下:

     

    9.递归思想

    方法递归的三个必要条件:
                 1). 必须要有出口条件
                 2). 必须满足一些规律

                 3). 必须要有方法

    实例如下:


    展开全文
  • java源码包---java 源码 大量 实例

    千次下载 热门讨论 2013-04-18 23:15:26
     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...
  • JAVA IO流

    2020-04-24 14:53:32
    12. IO流 文件操作的简介 操作磁盘上的某⼀个⽂件或者⽂件夹。可以对他们进⾏创建、删除、移动、属性获取、属性设置等操 ...绝对路径:从磁盘的根⽬录开始,⼀层层的向查找,直到找到这个⽂件。 相对...

    12. IO流

    文件操作的简介

    操作磁盘上的某⼀个⽂件或者⽂件夹。可以对他们进⾏创建、删除、移动、属性获取、属性设置等操

    作。但是,并不包含读取⽂件的内容,拷⻉⽂件。

    在Java中,使⽤ java.io.File 类描述⽂件(夹)。

    绝对路径和相对路径

    路径:⽤来描述⼀个⽂件所存在的地址,可以分为 绝对路径 和 相对路径。

    绝对路径:从磁盘的根⽬录开始,⼀层层的向内查找,直到找到这个⽂件。

    相对路径:某⼀个⽂件,相对于指定⽂件的路径(),在项目中,所有的相对路径都是针对项目的根目录的,例:File file = new File(“src\out\day23.java”)。

    路径表示 优点 缺点
    绝对路径 ⽤来表示⼀个路径,只要还在这个磁盘上,肯定可以找到指定的⽂件的。 ⼀旦换⼀个⽂件系统,此时这个路径表示的⽂件将⽆法找到。
    相对路径 只要两者的相对位置不变,⽆论在哪⼀个⽂件系统中,都可以找到这个⽂件。 ⽤来表示路径,只要两者的相对位置发⽣了改变,这个⽂件将⽆法找到。

    12.1 IO流的简介

    流:在文件和程序之间建立的让数据在其中流通(单向流动)的管道,就是一个流对象。

    IO流:Input、Output,输入输出。

    使用IO流,实现对磁盘上的某个文件进行读写的操作。

    IO流依据不同的分类方式可分为不同类型。

    按方向划分 按流中的数据单位划分
    输入流 字节流
    输出流 字符流

    必须掌握的流:父类流,Java中的流非常多,但均继承自以下四个父类之一。

    父类流 含义
    InputStream 字节输入流
    OutputStream 字节输出流
    Reader 字符输入流
    Writer 字符输出流

    注意事项:

    1. 上述四个⽗类流,他们都是抽象类,不能直接实例化对象,需要借助⼦类对象。
    2. 流对象⼀旦实例化完成,此时这个流是会持有这个⽂件的。此时将不能对这个⽂件进⾏某些操作。
    3. ⼀个流在使⽤结束后,⼀定要释放流资源。

    12.2 File类

    File:对磁盘上某一文件(目录)的描述,因为IO流需要对文件进行操作,因此在使用IO流的时候,一定会使用到File类。File类还包含若干对文件的操作方法。

    File类在Java.io包里

    关于⽬录分隔符,在不同的操作系统中,不⼀样。在windows中,使⽤ \ 作为⽬录分隔符,但是,在⾮windows的操作系统中,例如:Linux、Unix,使⽤ / 作为⽬录分隔符。

    关于路径分隔符,在不同的操作系统中,不⼀样。在windows中,使⽤ ; 作为路径分隔符,但是,在⾮windows的操作系统中,例如:Linux、Unix,使⽤ : 作为路径分隔符。

    静态属性 描述
    separator 根据不同的操作系统,返回不同的目录分隔符(字符串)
    pathSeparatorChar 根据不同的操作系统,返回不同的目录分隔符(字符)
    pathSeparator 根据不同的操作系统,返回不同的路径分隔符(字符串)
    pathSeparatorChar 根据不同的操作系统,返回不同的路径分隔符(字符)
    Windows操作系统 非Windows操作系统
    目录分隔符 \ /
    路径分隔符 ; :
    构造方法 描述
    File(String pathname) 通过文件的路径来实例化一个File对象
    File(String parent,String child) 拼接两个路径得到一个完整的路径
    File(File parent,String child) 根据一个父级文件和子路径得到一个新的File对象

    File文件相关操作:

    public class Program1 {
    	public static void main(String[] args) {
    		// 1.关于文件的路径
    		// 不同操作系统内使用的目录分隔符是不同的,Windows中是符号:\ ,路径分隔符也不同,Windows中的是符号:;
    		String a = File.separator;
    		char b = File.pathSeparatorChar;
    		String c = File.pathSeparator;
    		char d = File.pathSeparatorChar;
    		
    		File file = updataInfo();
    		getInfo(file);
    		String path = "E:\\软件目录\\Eclipse\\JAVA";
    		show(path);
    		
    	}
    	//关于File对象的操作
    	private static File updataInfo() {
    		//创建文件
    		// 构造方法1
    		File file1 = new File("E:\\软件目录\\Eclipse\\JAVA\\新建文件1");
    		// 构造方法2
    		File file2 = new File("E:\\软件目录\\Eclipse","JAVA\\新建文件2"); // 不一定从磁盘开始
    		try {
    			//返回尝试创建的结果
    			boolean result1 = file1.createNewFile();
    			if (result1) {
    				System.out.println("文件创建成功");
    			} else {
    				System.out.println("文件创建失败");
    			}
    			
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		//2.1创建文件夹(只能创建一级目录)并返回创建结果,如果创建成功,会返回true
    		// 创建失败原因:
    		// 指定路径下,已经有这个⽂件了。
    		// 没有⽗级⽬录的写权限
    		// ⽗级路径不存在
    		//返回尝试创建的结果
    		boolean result2_1 = file2.mkdir();
    		//2.2创建文件夹(可以创建多级目录)
    		//返回尝试创建的结果
    		boolean result2_2 = new File("E:\\软件目录\\Eclipse","JAVA\\新建文件夹2\\新建文件夹2_2").mkdirs();
    		//3.删除一个文件或一个空的文件夹(非空文件夹删不掉)
    		//该删除操作永久删除,不会进入回收站
    //		new File("E:\\软件目录\\Eclipse\\JAVA\\新建文件1").delete();
    		//4.重命名一个文件(同时移动一个文件的位置)
            // 失败的情况:重命名的⽂件已存在
    		// 源⽂件不存在
    		System.out.println(file2.renameTo(new File("E:\\软件目录\\Eclipse","JAVA\\新建文件夹2_2")));
    		return file1;
    	}
    	
    	// 常用关于File对象若干属性的获取方法
    	private static void getInfo(File file1) {
    		// 1.判断文件是否存在
    		boolean boolean1 = file1.exists();
    		// 2.判断一个路径指向的空间是否是一个文件
    		boolean boolean2 = file1.isFile();
    		// 3.判断一个路径指向的空间是否是一个文件夹
    		boolean boolean3 = file1.isDirectory();
    		// 4.文件权限判断
    		boolean boolean4_1 = file1.canRead(); // 判断文件是否可读
    		boolean boolean4_2 = file1.canWrite(); // 判断文件是否可写
    		boolean boolean4_3 = file1.canExecute(); // 判断文件是否可执行
    		// 5.判断文件是否是隐藏文件(隐藏文件以 . 开头)
    		boolean boolean5 = file1.isHidden();
    		// 6.获取文件的大小(字节)
    		Long long6 = file1.length();
    		// 7.获取文件的名字
    		file1.getName();
    		// 8.获取文件的路径
    		String string8_1 = file1.getPath(); // 相对路径:相对于某文件夹至该文件的路径
    		// 注:在Eclipse中,相对路径默认是相对于当前项目而言的
    		String string8_2 = file1.getAbsolutePath(); // 绝对路径:从磁盘的根目录至该文件
    		// 9.获取父级路径(路径字符串)
    		String string9 = file1.getParent();
    		// 10.获取描述父级文件的FIle类
    		File file10 = file1.getParentFile();
    		// 11.获取上次修改的时间
    		Date date11 = new Date(file1.lastModified());
    		System.out.println(date11);
    	}
    	//查询某一文件夹下所有的子文件夹
    		private static void show(String path) {
        	//指定的路径做出File对象
        	File file = new File(path);
        	//1.列举一个目录下所有文件的名字
        	String[] files1 = file.list();
        	//2.listFiles(FileFilter filter)
            //将file文件夹下的所有文件都带入到方法中,返回 返回值为true的文件构成的字符串数组
        	//File file:文件夹名字
        	//String name:子文件夹的名字
    		// 获取⼀个路径下满⾜条件的⽂件
    		File[] files = file.listFiles(f -> !f.isHidden() && f.length() > 100 * 1024 *1024);
            //例:列举出指定目录下所有的chw格式文件
                //f:父类目录
                //s:文件名
            String[] files2 = file.list((f,s)->s.endsWith(".chw"));
            //3.获取一个文件夹中所有的文件(返回所有子文件构成的File数组)
            File[] file3 = file.listFiles();
            //将file文件夹下的所有文件都带入到方法中,返回 返回值为true的文件构成的File数组
            File[] file4 = file.listFiles(f->f.getName().endsWith(".mp4"));
            //3.list()获取到⼀个路径下所有的⼦⽂件,以 String[]的形式返回,数组中存储的是⽂件的名字
    		String[] files = file.list();
    		Arrays.stream(files).forEach(System.out::println);
        }
    }
    

    URI:

    协议头,例:http:// ftp:// smb://

    主机,例:www.baidu.com

    端口,例: :8080/

    访问文件的路径,例:root/second/third/…/a.java

    分隔文件和参数列表:?

    参数列表,例:username=xxx&passwd=123

    12.3 InputStream、OutputSteam

    重点:(容易出现乱码)

    如何使用InputStream进行文件的读取

    如何使用OutputStream进行文件的写操作

    声明一个字节流对象:

    public class Program1 {
    	public static void main(String[] args) {
    		//字节输入流:读取某个文件中的数据
    //		InputStream is = new FileInputStream("file\\source");
    //		InputStream is = new FileInputStream(new File("file\\source"));
    		//实际使用中,先声明一个InputStream
    		InputStream is = null;
    		try {
    			//实例化一个输入流
    			is = new FileInputStream("file\\source");
    //			E:\软件目录\Eclipse\JAVA\TestProgram\file\source
    //			E:\软件目录\Eclipse\JAVA\TestProgram\src\bbinary\Program1.java
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    		finally {
    			//一个流若不再使用,一定要关闭它,否则不允许对文件进行其他操作,例:删除
    			try {
    				is.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		System.out.println(new File("file\\source").delete());
    	}
    }
    

    注:所有的流在使用结束后一定要立即关闭

    方案一:try代码段结束前加 对象.clear()

    方案二:InputStream已经继承了Autocloseable接口可以在try后,大括号前添加小括号,将流的声明放在小括号内

    注意事项:过了try代码段,流就关闭了,此时一切对流的操作都无效

    语法进阶:

    public class Program2 {
    	public static void main(String[] args) {
    		//实例化 流对象的进阶语法(不需要手动关闭,因为try后小括号的代码段伴随try的开关):
    		try(InputStream is = new FileInputStream("file\\source")) {
    			
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e1) {
    			e1.printStackTrace();
    		}
    	}
    }
    

    通过流对象读取某文件的内容:

    public class Program3 {
    	public static void main(String[] args) {
    		//读取流中的数据:
    		//int read():读取流中的数据,每次调用读取一个字节,返回值代表本次读取到的内容
    		//int read(byte[] array):读取流中的数据,将读取到的数据存入一个数组,返回值代表本次读取到多少个字节数据
    		//1.实例化了一个流的对象,在文件和程序之间建立了一个管道
    		try (InputStream is = new FileInputStream("file\\source")){
    			//2.实例化一个字节数组,循环读取一个文件中的数据
    			byte[] array = new byte[10];
    			//3.为防止最后一组array填不满,而多出乱码等情况
    			//需声明一个变量,用来记录每次读到了多少数据
    			int length = 0;
    			//4.循环读取流中的数据
    			while ((length = is.read(array))!=-1) {		//is.read(array)返回该组array读取的字节数(无数据则返回-1),无参read函数代表每次读取一个元素
    				//将字节数组中的数据进行处理
    				String string = new String(array,0,length);//为防止最后一组array填不满,而多出乱码
    				System.out.print(string);
    			}
    			
    		} catch (Exception e) {
    			e.printStackTrace();;
    		}
    	}
    }
    
    

    通过流对象某文件进行写操作

    public class Program4 {
    	public static void main(String[] args) {
    		//实例化一个流对象,连接程序和指定的文件
    		//在写程序的操作中,若目标文件不存在,则会自动创建一个文件
    		//FileOutputStream实例化的时候,会有一个boolean append参数来控制新的写操作是否会覆盖原有内容
    		//append:true->在原有内容的后面追加新的数据;
    		//append:false->删除原有数据并写入新数据,不写则默认值为false;
    		try (OutputStream os = new FileOutputStream("file\\target",true)){
    			//如何进行写操作
    			//注意:写操作并不是将数据写入到文件中,而是写入到输出流,再由输出流将数据流动到文件中
    			os.write("你好,世界 hello,world".getBytes());
    			//注意:每次写操作后,都需要添加一个flush操作
    			//目的:冲刷数据流,加速流中的数据流动到文件中
    			//在关闭流的时候,系统会自动调用一次flush操作以确保流中的数据都已经流动到文件中
    			os.flush();
    			System.out.println("写数据完成!");
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    		catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    OutputStream注意事项:

    1. 使⽤⼀个输出流,建⽴程序与⽂件的连接。**如果这个⽂件不存在,会自动的创建。**但是在创建的时候,要求⽗级⽂件夹是存在的。如果父级文件夹不存在,则这个⽂件也会创建失败,会出现FileNotFoundException 异常。
    2. 使⽤流建议⽂件与程序的连接,当这个流第⼀次向⽂件中写数据的时候,会将⽂件中原来的数据全部清除,再写⼊新的数据。从第⼆次写开始,将会在原来的基础上向后追加。

    拷贝文件

    public class Program5 {
    	public static void main(String[] args) {
    		copy("E:\\文件目录\\source.xlsx","C:\\Users\\陈永豪\\Desktop\\garget.xlsx");
    	}
    	//从文件名source拷贝至文件名target的文件中
    	private static void copy(String source,String target) {
    		//循环读取文件中的数据,将读取到的数据写入到目标文件
    		try (InputStream is = new FileInputStream(source);OutputStream os = new FileOutputStream(target)){
    			//1.实例化一个字节数组,用来存储每次读到的数据
    			byte[] array = new byte[1024];
    			//2.声明一个变量,存储每次读取到的字节数量
    			int length = 0;
    			//3.循环读取
    			while ((length = is.read(array))!=-1) {
    				//4.将读取到的数据写入到输出流中
    				os.write(array,0,length);
    				os.flush();
    			}
    			System.out.println("文件拷贝完成");
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    加密操作:

    public class Program6 {
    	public static void main(String[] args) {
    		String file = "E:\\文件目录\\source.xlsx";
    		lock(file);
    	}
    	//加密代码
    	private static void lock(String file) {
    		//思路:在当前路径下,创建一个新的文件,命名为: 原文件的命名.lock
    		//例:source.mp4->source.mp4.lock
    		String lockFilePath = file +".lock";
    				try (InputStream is = new FileInputStream(file);OutputStream os = new FileOutputStream(lockFilePath)){
    					byte[] array = new byte[1024];
    					int length = 0;
    					while ((length = is.read(array))!=-1) {
    						array = lock(array);
    						os.write(array,0,length);
    						os.flush();
    					}
    					System.out.println("文件拷贝完成");
    				} catch (FileNotFoundException e) {
    					e.printStackTrace();
    				}catch (IOException e) {
    					e.printStackTrace();
    				}
    				new File(file).delete();
    		}
    		private static byte[] lock(byte[] array) {
    		int secury = 1234;
    		for (int i = 0; i < array.length; i++) {
    			array[i] ^=secury;
    		}
    		return array;
    	}
    }
    

    解密操作:

    public class Program7 {
    	public static void main(String[] args) {
    		String file = "E:\\文件目录\\source.xlsx.lock";
    		copyAndSecure(file);
    		
    	}
    	private static void copyAndSecure(String file) {
    		String lockFilePath = file.substring(0,file.length()-5);
    		try (InputStream is = new FileInputStream(file);OutputStream os = new FileOutputStream(lockFilePath)){
    			byte[] array = new byte[1024];
    			int length = 0;
    			while ((length = is.read(array))!=-1) {
    				array = lock(array);
    				os.write(array,0,length);
    				os.flush();
    			}
    			System.out.println("文件拷贝完成");
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}catch (IOException e) {
    			e.printStackTrace();
    		}
    		new File(file).delete();
    	}
    	private static byte[] lock(byte[] array) {
    		int secury = 1234;
    		for (int i = 0; i < array.length; i++) {
    			array[i] ^=secury;			//位异或(两次异或得原码,即第二次解密)
    		}
    		return array;
    	}
    }
    

    12.4 Reader、Writer

    Reader、Writer是所有的字符流的父类,一般情况下字符流是用来操作文本的

    Reader:是一个输入流。

    Writer:是一个输出流。

    字符流,流中流动的数据的单位是–字符,一般是对文本进行操作。

    使用字符流在读取数据的时候,过程与字节流读取基本相同,不同点在于:使用字节流读取数据,需要用到一个字节数组,将读取到的数据存入到一个字节数组中;使用字节流读取数据,需要用到一个字符数组,将读取到的数据存入到一个字符数组中。

    将数据读取到字符输入流

    public class Program1 {
    	public static void main(String[] args) {
    		//1.实例化一个FileReader对象并向上转型为Reader类型
    		try (Reader reader = new FileReader("file\\source")) {
    			//2./实例化一个字符数组,用来存储每次从流中读取的数据
    			char[] array = new char[10];
    			//3.声明一个变量,用来存储每次读取到多少个数据(字符)
    			int length = 0;
    			//4.循环读取
    			while ((length=reader.read(array))!=-1) {
    				//5.将字符数组中的元素拼接成字符串
    				String string = new String(array,0,length);
    				System.out.println(string);
    			}
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    将数据写入到字符输出流

    public class Program2 {
    	public static void main(String[] args) {
    		try (Writer writer = new FileWriter("file\\target",true)) {
    			writer.write("哈哈哈哈哈");
    			writer.flush();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    字节流与字符流的区别:

    1. 字节流可以用于任何类型数据的输入输出,字符流只能用于文本数据的输入输出
    2. 对于文本数据字节流和字符流都能用,只不过用字符流更方便,因为字符流处理了编码

    12.5 缓冲流

    对父类流进行了一层包装,添加了一个缓冲区(Buffer),目的是提高流操作的效率。

    BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter

    在所有的缓冲流中,都有一个属性用来记录所包装的流对象,在缓冲流的close中,会对包装的流对象进行自动的关闭操作(使用完缓冲流的时候,通过关闭缓冲流即可

    缓冲字节流的读操作:

    public class Program1 {
        public static void main(String[] args) {
            //实例化
            //通过一个InputStream实例化一个BufferedInputStream
            try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream("file\\source"))) {
                //1.BufferedInputStream继承自InputStream,所以本质上还是字节流,因此读取数组还需字符数组
                byte[] array = new  byte[1024];
                //2.声明一个变量,用来存储每次读取到多少个字节的数据
                int length = 0;
                //3.循环读取
                while ((length=bis.read(array))!=-1) {
                    //4.将读取到的数据进行处理
                    String string = new String(array,0,length);
                    System.out.print(string);
                }
            }catch (FileNotFoundException e){
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    

    缓冲字节流的写操作:

    // 1、通过⼀个 OutputStream,实例化⼀个 BufferedOutputStream
    // 此时,BufferedOutputStream在进⾏关闭的时候,会对内部的 字节输出流 进⾏
    try (BufferedOutputStream bos = new BufferedOutputStream(new
    	FileOutputStream("files\\dst"))) {
     	// 将数据写⼊到输出流中
     	bos.write("hello".getBytes());
        bos.flush();
    } catch (IOException e) {
     	e.printStackTrace();
    }
    

    缓冲字符流的读操作:

    public class Program2 {
        public static void main(String[] args) {
            //实例化
            //通过一个Reader实例化一个BufferedReader
     		//在使⽤完 BufferedInputStream 之后,直接关闭 bis 即可,不需要⼿动关闭 InputStream字节流
            try(BufferedReader br = new BufferedReader(new FileReader("file\\source"))) {
                //1.声明一个String类型的变量,用来存储每次读取一行的数据
                String line = null;
                //2.循环读取
                //readLine():读取流中的一行数据,行的区分,是按照\n计算的,但读取的内容不包含换行符\n(读取的内容在一行中)
                while ((line=br.readLine())!=null) {
                    //3.将读取到的数据进行处理
                    System.out.println(line);
                }
            }catch (FileNotFoundException e){
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    

    缓冲字符流的写操作:

    public class Program3 {
        public static void main(String[] args) throws IOException {
            try (BufferedWriter bw = new BufferedWriter(new FileWriter("file\\target",true))){
                bw.write("后宫佳丽三千人,三千宠爱在一身");
                //在BufferedWriter:增加了一个方法:newLine();
                //在流中写一个换行符,等价于write方法后加一个 \n
                bw.newLine();
                bw.write("缓歌漫舞凝丝竹,尽日君王看不足");
                bw.flush();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    

    12.6 Scanner类

    扫描器类,从一个流或者从一个文件中扫描数据(不一定是控制台)。

    12.6.1 标准输入、输出流

    System.in:系统标准字节输入流,本质来讲是一个InputSteam,但是这个对象是系统自己实例化的。连接了程序和控制台,在内部封装了一些逻辑,可以阻塞线程,等待用户的输入,直到用户输入完成,可以继续进行其他的操作。

    System.out:系统标准输出流,本质来讲是一个打印流(printSteam),可以将程序中的数据输出到控制台,也可以从控制台向指定文件输入内容,其实连接控制台的操作是由打印流完成的。

    重定向标准输入流:

    // 在重定向输⼊流之前,先备份原来的输⼊流,以便使⽤结束之后,恢复
    InputStream original = System.in;
    // 实例化⼀个 InputStream,读取⼀个⽂件中的数据
    try (BufferedInputStream inputStream = new BufferedInputStream(new
    FileInputStream("files\\src"))) {
     	// 重定向标准输⼊流
     	System.setIn(inputStream);
     	// 此时,再使⽤到 System.in 的时候,其实⽤的是 inputStream,此时从指定文件中读取数据到控制台。
     	Scanner scanner = new Scanner(System.in);
     	while (scanner.hasNextLine()) {
     	System.out.println(scanner.nextLine());
     	}
     	scanner.close();
    } catch (IOException e) {
     	e.printStackTrace();
    }
    // 因为此时重定向了标准输⼊流,此时的标准输⼊流就是上⽅try中的inputStream
    // 但是!!! try结构结束之后,这个inputStream会被close。
    Scanner scanner = new Scanner(System.in);
    while (scanner.hasNextLine()) {
     	System.out.println(scanner.nextLine());
    }
    scanner.close();
    

    标准输入流的相关操作:

    public class Program1 {
        public static void main(String[] args) {
            //Scanner类:读取指定文件中的数据
            try (Scanner scanner = new Scanner(new File("file\\source"))) {
                //循环并判断是否读完
                while (scanner.hasNextLine()) {
                    String string = scanner.nextLine();
                    System.out.println(string);
                }
                //Scanner对象在使用完成后,是需要关闭的
                scanner.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    

    标准输出流的相关操作:

    public class Program2 {
        public static void main(String[] args) {
            //备份最初始的标准输出流
            PrintStream tmp = System.out;
            //1.实例化一个打印流对象
            try (PrintStream ps = new PrintStream(new FileOutputStream("file\\log",true));){
                //重定项系统标准输出流
                System.setOut(ps);
                System.out.println("hello world");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            System.setOut(tmp);
            System.out.println("你好 世界");
        }
    }
    

    12.7 转换流

    全称——字节字符转换流,底层的实现是字节流,这样能保证数据读写过程中不会出现字节丢失问题,上层提供的操作⽅法,是字符流的方法。所以,转换流保留了字符操作的便利性,又有字节流的可靠性。最常⻅的使⽤场景,就是读取指定的字符集的⽂本⽂件。

    当我们需要读取一个文本数据的时候,由于不同字符集(编码格式)的存在,会导致读取的过程中,出现乱码的问题,可以使用转换流解决这个读写过程中的字符乱码问题。

    使用场景:

    1. 使用指定的字符集,读取某文件中的数据
    2. 使用指定的字符集,向一个指定的文件中写数据。

    涉及到的两个类:InputStreamReader、OutputStreamWriter

    用转换流和指定的字符集对某一文本做读操作:

    public class Program1 {
        public static void main(String[] args) {
            //InputStream和一个指定的字符集实例化一个转换流对象
            try (InputStreamReader reader = new InputStreamReader(new FileInputStream("file\\source2"), "gbk") ){
                //1.从流中读取数据
                char[] array = new char[1024];
                int length = 0;
                while ((length=reader.read(array))!=-1){
                    System.out.println(new String(array,0,length));
                }
            }catch (UnsupportedEncodingException e){        //捕捉不支持的编码格式
                e.printStackTrace();
            }
            catch(FileNotFoundException e){
                e.printStackTrace();
            }
            catch (IOException e){
                e.printStackTrace();
            }
            //法二:以下读写会稍微快一点
    //        try {
    //            BufferedReader reader = new BufferedReader(new BufferedReader(new InputStreamReader(new FileInputStream("file\target"))))
    //        }catch (UnsupportedEncodingException e){
    //            e.printStackTrace();
    //        }catch (IOException e){
    //            e.printStackTrace();
    //        }catch (FileNotFoundException e) {
    //            e.printStackTrace();
    //        }
        }
    }
    
    

    用转换流和指定的字符集对某一文本做写操作:

    public class Program2 {
        public static void main(String[] args) {
            //1.实例化一个采用了指定字符集的输出流
            try(OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("file\\target",true),"utf-8")){
                //2.将数据写入到文本中
                osw.write("\n落霞与孤鹜齐飞,秋水共长天一色");
                osw.flush();
            }catch (UnsupportedEncodingException e){
                e.printStackTrace();
            }catch (FileNotFoundException e){
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    

    12.8 Properties

    Propeties是集合框架中的一个类,父类是Hashtable,主要作用是读写一个 .properties文件。

    properties文件,是一个属性列表文件,在这个文件中,可以存储一些简单的配置数据。

    .properties文件的规则:

    1. 是以键值对的形式进行存储的,键和值以等号分隔,不需要加空格,不同的键值对以换行分隔。
    2. 重点:所有的键值对都是以String类型存储的,但不需要也不能写双引号。
    3. 不能写中文(注释可以)
    4. 除了键、等号、值,不需要出现其他任何字符

    使用Properties来读写文件:

    public class Program {
        public static void main(String[] args) {
            //实例化一个Properties类的对象
            Properties properties = new Properties();
            try {
                //1.从指定的流中读取数据到集合中
                properties.load(new BufferedReader(new FileReader("file\\config.properties")));
                //具有所有Map方法,例:
                properties.remove("name");
                //2。新添键值对
                properties.setProperty("gender","unknown");
                //3.遍历这个集合
                properties.forEach((key,value)-> System.out.printf("%s=%s\n",key,value));
                //4.将一个Properties文件中的数据,写入到指定的Properties文件中
                //参数:OutputStream out:文件的存储路径, String comments:提交日志
                properties.store(new FileOutputStream("file\\config.properties"),"log");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    12.9 对象流

    将程序中的某⼀个对象,以⽂件的形式序列化到本地。

    两个常用流:ObjectInputStream、ObjectOutputStream

    作用:将程序中的某些对象,以文件的形式序列化到本地。(如果没有持久化存储,这个对象将在程序结束的时候被销毁)

    序列化:将对象以文件的形式保存到本地,用ObjectOutputStream。

    反序列化:将本地的某个文件存储的信息读取出来并给某一个对象的属性赋值,用ObjectInputStream。

    注意事项:

    1. NotSerializableException异常:需要序列化的对象对应的类(包含内部类),必须要实现 Serializable 接口。
    2. 如果需要序列化多个对象,不能通过public FileOutputStream(String name, boolean append)方法拼接对象的信息,而是将所有对象存入一个集合,将这个集合整体序列化到本地。

    通过对象进行序列化和反序列化的操作:

    public class Program {
        public static void main(String[] args) {
            //1.实例化一个Person对象
            Person person = new Person("xiaoming",20,Gender.Male,new Dog("小白",2));
            //序列化
            save(person);
            Person xiaoming = loadData();
            System.out.println(xiaoming);
    
        }
        //序列化:将一个Person对象以文件的形式保存到本地
        private static void save(Person person){
            //1.实例化一个ObjectOutputStream对象
            try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("file\\person"))){
                //2.序列化
                oos.writeObject(person);
                oos.flush();
                System.out.println("序列化完成");        //生成的二进制文件乱码
            }catch (FileNotFoundException e){
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //反序列化:从本地序列化的文件中读取数据,转成对象并返回
        private static Person loadData(){
            //1.实例化一个ObjectInputStream对象
            try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("file\\person"))){
                //2.反序列化
                Object object = ois.readObject();
                //3.判断object对象是否是一个person对象
                if(object instanceof Person){
                    return (Person)object;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    class Person implements Serializable {
        private String name;
        private int age;
        private Gender gender;
        private Dog pet;
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", gender=" + gender +
                    ", pet=" + pet +
                    '}';
        }
    
        public Person(String name, int age, Gender gender) {
            this.name = name;
            this.age = age;
            this.gender = gender;
        }
    
        public Person(String name, int age, Gender gender, Dog pet) {
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.pet = pet;
        }
    }
    class Dog implements Serializable{
        private String name;
        private int age;
        public Dog(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    
    

    12.10 NIO(重点,常见)

    NIO:New IO、Non-Blocking IO(非阻塞型IO)

    是JDK1.4出现的用来替代传统的IO的一套新的API。NIO与传统的IO有相同的功能,但操作方式不一样,NIO是面向缓冲区(Buffer)、基于通道(Channel)。

    在JDK1.7之后,添加了若干新的元素,被称为NIO.2

    NIO和IO的区别:

    • NIO是面向缓冲区的,IO是面向流的
    • NIO是非阻塞型,IO是阻塞型
    12.10.1 缓冲区Buffer(双向流动)

    缓冲区,其实是一个容器,类似于一个数组,这个容器中只能存储基本数据类型的数据。

    缓冲区,按照存储的数据类型不同,可以分为以下几个(缓冲区)类:

    ByteBuffer ShortBuffer IntBuffer LongBuffer
    FloatBuffer DoubleBuffer CharBuffer

    以上缓冲区均拥有相同的父类-Buffer类,所以这些类有相同的方式来存储和管理数据。

    注意:

    1. 没有存储boolean的缓冲区
    2. Buffer是一个抽象类,不能实例化对象。因此,在实际应用中,用的还是子类的对象。

    常见操作:

    1. 获取缓冲区的对象:

      由于缓冲区都是抽象类,不能直接通过new的方式实例化,需要通过静态方法allocate()获取对象。

      注:缓冲区是一个容器,对缓冲区的操作也就只有读和写操作。

      缓冲区的两种模式:读模式 和 写模式

      读模式:在这个模式下,一般情况下是进行缓冲区的数据读取操作。

      写模式:在这个模式下,一般情况下是进行缓冲区的数据写入操作。

    2. 缓冲区的常见属性

      1. position:当前操作的下标

      2. limit:能够操作的空间数(是一次读写操作的上限,当切换成读模式时,数值才会改变)

      3. capacity:缓冲区的容量

      4. mark:标记,在当前缓冲区的position位置中添加一个标记,配合reset方法,使position重置为mark标记位。

        以上四个属性都是private权限,因此不能直接获取

        四个属性的大小关系:

        mark<=position<=limit<=capacity

        一旦不满足以上关系就会出现异常

    3. 缓冲区的常见操作:

      1. allocate(int capacity)

        因为所有的缓冲区,都是抽象类,不能实例化对象。因此,缓冲区的开辟,需要通过这个⽅法,或者allocateDirect() 进⾏开辟。在开辟缓冲区的时候,需要传⼊⼀个参数,这个参数,就代表这个缓冲区的最⼤容量。如果类⽐到数组,这⾥就是数组的⻓度。这个容量,⼀旦确定了,缓冲区开辟了,就不能改变了。缓冲区,分为“读”模式,和“写”模式。

      2. put():往缓冲区写数据,如果写的数据超出缓冲区的容量,会出现异常BufferOverflowException。

      3. flip():将缓冲区切换成读模式

      4. get():从缓冲区读取数据,若读取的数据超出limit,则会出现异常BufferUnderflowException。

      5. rewind():重置操作,将position重置为0,重置mark(写模式时limit的范围也会重置为0,读模式时limit不变)

      6. clear():清空,将position、limit、capacity、mark都重置为初始状态,并使缓冲区切换到写模式。

      7. mark():在当前的position位置添加一个标记。

      8. reset():重置position为mark的位置(如果没有设置mark值就reset则会异常)

      常见操作:

      public class Program1 {
          public static void main(String[] args) {
              //通过allocate方法获取一个缓冲区对象
              ByteBuffer buffer = ByteBuffer.allocate(10);
              //
              System.out.println("------allocate()-------");
              System.out.println("capacity = "+buffer.capacity());      //缓冲区的capacity
              System.out.println("limit = "+buffer.limit());
              System.out.println("position = "+buffer.position());
              //向缓冲区中添加数据
              buffer.put("hello".getBytes());
              System.out.println("------put()-------");
              System.out.println("capacity = "+buffer.capacity());
              System.out.println("limit = "+buffer.limit());
              System.out.println("position = "+buffer.position());
              //重置position
              buffer.rewind();
              System.out.println("------rewind()-------");
              System.out.println("capacity = "+buffer.capacity());
              System.out.println("limit = "+buffer.limit());
              System.out.println("position = "+buffer.position());
      //        //切换读模式
      //        buffer.flip();
      //        System.out.println("------flip()-------");
      //        System.out.println("capacity = "+buffer.capacity());
      //        System.out.println("limit = "+buffer.limit());
      //        System.out.println("position = "+buffer.position());
              //从缓冲区中读取数据
              byte[] dst= new byte[buffer.limit()];
              buffer.get(dst);       //无参方法时得到一个字节,可以通过新建字节数组一次性读取多个字节
              System.out.println(new String(dst));
              System.out.println("------get()-------");
              System.out.println("capacity = "+buffer.capacity());
              System.out.println("limit = "+buffer.limit());
              System.out.println("position = "+buffer.position());
              buffer.rewind();
              System.out.println("------rewind()-------");
              System.out.println("position = "+buffer.position());
              System.out.println("limit = "+buffer.limit());
              byte[] dst2 = new byte[2];
              buffer.get(dst2);
           System.out.println("position = "+buffer.position());
              //在当前位置添加一个标记
              buffer.mark();
              buffer.get(dst2);
              System.out.println(new String(dst2));       //ll
              buffer.reset();
              System.out.println("position = "+buffer.position());
              buffer.get(dst2);
              System.out.println(new String(dst2));       //ll
          }
      }
      

      其实缓冲区就是一个容器,对缓冲区的操作就是读和写。所谓两种模式只是从逻辑上分类。

      出于规范在对应模式进行对应操作。

      所谓的flip()方法、clear()方法只是重置了position和limit的值,本质上出发,缓冲区没有所谓的读和写模式。也就是说:“读模式”下可以进行写操作;“写模式”下可以进行读操作。

      public class Program2 {
          public static void main(String[] args) {
              //开辟一个缓冲区
              ByteBuffer buffer = ByteBuffer.allocate(10);        //limit:10,position:0
              buffer.put("hello".getBytes());                     //limit:10,position:5 hello
      //        buffer.flip();                                      //limit:5,position:0
              buffer.rewind();                                    //limit:10,position:0
              byte[] dst = new byte[5];
              buffer.get(dst);                                    //limit:10,position:5
              System.out.println(new String(dst));                //hello
      //        buffer.get(byte);                                   //limit:10,position:10
              buffer.flip();                                      //limit:5,position:0
              buffer.put("world".getBytes());                     //limit:5,position:5 world
              buffer.clear();                                     //limit:10,position:0
              buffer.get(dst);
              System.out.println(new String(dst));                //world
          }
      }
      

      直接缓冲区、非直接缓冲区

      区别:

      1. 直接缓冲区,使用allocate方法实现。

        直接缓冲区,使用allocateDirect方法开辟。

      2. 非直接缓冲区,是建立在JVM内存中的。

        直接缓冲区是建立在物理内存中的。

      3. 直接缓冲区的读写效率高。

        虽然直接缓冲区的读写效率远远高于非直接缓冲区,但实际使用中,还是以非直接缓冲区的使用为主。因为使用直接缓冲区有一些弊端:

        1. 由于直接缓冲区是建立在物理内存的,当我们需要进行写操作的时候,将数据从程序写入到直接缓冲区。此时程序已经丧失了对这个数据操作的可能性。这些数据什么时候写入到文件中,是由操作系统完成的。
        2. 直接缓冲区建立于物理内存,如果物理内存处理不佳,会导致内存泄漏。
        //开辟一个直接缓冲区
        //在物理内存中开辟一个大小1024的直接缓冲区
        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
        //验证一个缓冲区是否是直接缓冲区
        System.out.println(buffer.isDirect());
        
    12.10.2 通道Channel

    是一个文件和程序的连接。通道本身不负责数据的传递、数据的传递由缓冲区负责。

    通道(Channel)是程序与⽂件之间的连接,在NIO中,数据传递是由缓冲区完成的,通道不负责数据的传递。通道在 java.nio.channels 包中,常⻅的Channel⼦类有:

    本地⽂件通道:FileChannel

    ⽹络⽂件通道:SocketChannel、ServerSocketChannel、DatagramChannel

    Channel是一个接口,常用实现类:FileChannel

    FileChannel是一个抽象类,不能直接实例化对象。FileChannel对象的获取需要获得指定的途径:

    1. 可以使用支持通道的类,所提供的getChannel()方法来获取。
      1. 本地IO:FileInputStream、FileOutputStream
      2. ⽹络⽂件通道:Socket、ServerSocket、DatagramSocket
    2. 在NIO.2中,通过FileChannel类静态方法 open()获取通道。
    3. 在NIO.2中,使用Files类中的new方法。
    12.10.3 路径Path类

    一个用来描述文件路径的接口,在实际应用中,很少关心其实现类,Path对象的获取更多情况下,是通过一个工具类Paths获取的。

    Path.get(String first,String...more)
    

    方法的作用:会将参数列表中的每一个组成部分拼接起来,组成一个完整的路径,并返回描述这个路径的一个Path对象。

    三种通过NIO进行读写数据并传递的操作:

    /**
     * 使用 FileChannel.open() 方法
     *
     * Path: 是一个用来描述一个文件路径的接口。常见的使用方法:
     *       Paths.get(String first, String... more): 拼接文件路径,得到Path对象
     *
     * StandardOpenOption:
     *       READ           : 读文件
     *       WRITE          : 写文件
     *       APPEND         : 追加数据
     *       CREATE         : 如果没有这个文件,就创建一个文件;如果存在这个文件,就不做任何操作。
     *       CREATE_NEW     : 如果没有这个文件,就创建一个文件;如果存在这个文件,就抛异常。
     */
    public class Program1 {
        private static String src = "file\\source";     //源文件路径
        private static String dst = "file\\target";     //目标文件路径
    
        public static void main(String[] args) {
            //1.使用支持通道的类,所提供的getChannel()方法来获取。
            method01();
            //2.通过NIO.2中FileChannel类的静态方法open()打开一个通道
            method02();
            //3.通过NIO.2中的Files的new方法,开辟一个通道
            method03();
        }
        //1.使用支持通道的类,所提供的getChannel()方法来获取。
        private static void method01(){
            try (FileInputStream fis = new FileInputStream(src); FileOutputStream fos = new FileOutputStream(dst)){
                //提供的getChannel方法,获取通道
                FileChannel inChannel = fis.getChannel();
                FileChannel outChannel = fos.getChannel();
                //实例化一个缓冲区
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                while(inChannel.read(buffer)!=-1){          //将数据写入到缓冲区
                    //读取
                    buffer.flip();              //切换到读模式
                    outChannel.write(buffer);   //将数据通过outChannel通道,写入到指定的文件中
                    buffer.clear();
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        //2.通过NIO.2中FileChannel类的静态方法open()打开一个通道
        private static void method02(){
            FileChannel inChannel = null;        //选择StandardOpenOption枚举中你需要的操作
            FileChannel outChannel = null;
            try {
                //打开通道,读取src文件中的内容
                inChannel = FileChannel.open(Paths.get(src), StandardOpenOption.READ);
                //打开通道,将数据写入到dst中
                outChannel = FileChannel.open(Paths.get(dst),StandardOpenOption.WRITE,StandardOpenOption.CREATE,StandardOpenOption.READ);
                //如果使用非直接缓冲区读写数据,这个过程参考method01
                //以下是使用直接缓冲区进行数据的读写
                //使用内存映射文件
                MappedByteBuffer min = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
                MappedByteBuffer mout = outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());
                //对直接缓冲区进行读写
                byte[] array = new byte[min.limit()];
                min.get(array);
                mout.put(array);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(inChannel!=null){
                    try {
                        //关闭通道
                        inChannel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(outChannel!=null) {
                    try {
                        outChannel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        //3.通过NIO.2中的Files的new方法,开辟一个通道
        private static void method03() {
            FileChannel inChannel = null;
            FileChannel outChannel = null;
            try {
                inChannel = (FileChannel) Files.newByteChannel(Paths.get(src), StandardOpenOption.READ);
                outChannel = (FileChannel) Files.newByteChannel(Paths.get(dst), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
                //实现两个通道之间的数据传递(这种方式是使用直接缓冲区操作的)
                //法一:
    //            inChannel.transferTo(0,inChannel.size(),outChannel);
                //法二:
                outChannel.transferFrom(inChannel,0,inChannel.size());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inChannel != null) {
                    try {
                        //关闭通道
                        inChannel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (outChannel != null) {
                    try {
                        outChannel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    12.10.4 分散聚合

    分散:将数据写入到多个缓冲区,分散写入。

    聚合:从多个缓冲区中读取数据,聚合读取。

    public class Program2 {
        public static void main(String[] args) {
            try {
                FileChannel inChannel = FileChannel.open(Paths.get("file\\source"), StandardOpenOption.READ);
                FileChannel outChannel = FileChannel.open(Paths.get("file\\target"), StandardOpenOption.WRITE,StandardOpenOption.CREATE);
                //将多个缓冲区存入一个数组
                ByteBuffer[]buffers = new ByteBuffer[10];
                for (int i = 0; i < buffers.length; i++) {
                    buffers[i]=ByteBuffer.allocate(2014);
                }
                //分散写:将数据写入到多个缓冲区
                inChannel.read(buffers);
                //聚合读:读取多个缓冲区的数据
                outChannel.write(buffers);
    
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
    
    12.10.5 Files类

    是一个用来操作file的工具类。

    Files的常见操作:

    public class Program1 {
        public static void main(String[] args) {
            try {
                //1.创建文件
                Files.createFile(Paths.get("file\\a.txt"));
                //2.创建文件夹
                Files.createDirectory(Paths.get("file\\abc"));
                //3.创建多级目录
                Files.createDirectories(Paths.get("file\\abc\\a\\b\\c"));
                //4.删除文件(空文件夹):如果删除的文件(夹)不存在,则抛出异常
                Files.delete(Paths.get("file\\a.txt"));
                Files.delete(Paths.get("file\\abc\\a\\b"));
                //5.尝试删除文件(夹),返回操作结果
                boolean ret5 = Files.deleteIfExists(Paths.get("file\\a.txt"));
                //6.移动、重命名文件
                Files.move(Paths.get("file\\input"),Paths.get("file\\output"));
                //7.拷贝文件
                Files.copy(Paths.get("file\\source"),Paths.get("file\\dst"));
                //获取文件大小
                Files.size(Paths.get("file\\source"));
                //判断可读
                //判断可写
                //判断可执行
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    展开全文
  • java源码包2

    千次下载 热门讨论 2013-04-20 11:28:17
     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包Java zip压缩包查看程序源码 1个目标文件 摘要:Java...
  • java源码包3

    千次下载 热门讨论 2013-04-20 11:30:13
     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包Java zip压缩包查看程序源码 1个目标文件 摘要:Java...
  • java源码包4

    千次下载 热门讨论 2013-04-20 11:31:44
     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包Java zip压缩包查看程序源码 1个目标文件 摘要:Java...
  • Java程序监控系统关键指标 本文我们讨论如何使用...可以利用其根据文件路径获取文件系统一些关键信息且与操作系统无关,对windows或linux上对根分区进行检查。 ManagementFactory 类可以用来分析内存使用情况以及处...

    Java程序监控系统关键指标

    本文我们讨论如何使用Java核心API监控系统关键指标,如磁盘空间、内存使用率以及线程信息等。

    1. 内置 API 介绍

    File类用于查询特定磁盘信息,File类是文件或目录的抽象表示。可以利用其根据文件路径获取文件系统一些关键信息且与操作系统无关,对windows或linux上对根分区进行检查。

    ManagementFactory 类可以用来分析内存使用情况以及处理器信息。该工厂类可以获取管理bean(MXBeans)关于JVM的相关信息,我们主要用到MemoryMXBean和ThreadMXBean类。

    • MemoryMXBean

    MemoryMXBean表示JVM的内存系统上管理接口。JVM创建了该接口的单实例,可以调用getMemoryMXBean() 方法获取信息。

    • ThreadMXBean

    与MemoryMXBean类类似, ThreadMXBean 类是JVM线程系统管理接口。可以调用getThreadMXBean()方法获取相关线程的关键信息。

    2. API实现监控

    2.1. 磁盘使用率

    使用File类获取分区的关键信息,包括总磁盘空间、未分配的磁盘空间以及可用的磁盘空间,可用磁盘空间应该大于或等于未分配的磁盘空间。
    下面代码读取windows上的C盘:

    File cDrive = new File("C:");
    System.out.println(String.format("Total space: %.2f GB", (double)cDrive.getTotalSpace() /1073741824));
    System.out.println(String.format("Free space: %.2f GB",  (double)cDrive.getFreeSpace() /1073741824));
    System.out.println(String.format("Usable space: %.2f GB",  (double)cDrive.getUsableSpace() /1073741824));
    

    linux上根目录信息:

    File root = new File("/");
    System.out.println(String.format("Total space: %.2f GB",  (double)root.getTotalSpace() /1073741824));
    System.out.println(String.format("Free space: %.2f GB",  (double)root.getFreeSpace() /1073741824));
    System.out.println(String.format("Usable space: %.2f GB",  (double)root.getUsableSpace() /1073741824));
    

    默认情况下上述方法返回值单位是字节。一般需转为Gb使可读性更好。

    2.2. 内存使用率

    可以使用ManagementFactory工厂类的MemoryMXBean方法获取JVM内存情况。这里主要查询堆内存,当然非堆内存也可以获取。

    MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
    
    System.out.println(String.format("Initial memory: %.2f GB", (double)memoryMXBean.getHeapMemoryUsage().getInit() /1073741824));
    System.out.println(String.format("Used heap memory: %.2f GB", (double)memoryMXBean.getHeapMemoryUsage().getUsed() /1073741824));
    System.out.println(String.format("Max heap memory: %.2f GB", (double)memoryMXBean.getHeapMemoryUsage().getMax() /1073741824));
    System.out.println(String.format("Committed memory: %.2f GB", (double)memoryMXBean.getHeapMemoryUsage().getCommitted() /1073741824));
    

    代码主要返回堆初始内存、已使用内存、最大内存、可用内存。描述如下:

    • Initial: OS启动时JVM请求初始化的内存大小
    • Used: 当前JVM使用的内存大小
    • Max: JVM最大有效内存. 如果达到该限制值会抛 OutOfMemoryException 异常
    • Committed: 保证JVM可用内存大小

    2.3. CPU使用情况

    接下来我们使用ThreadMXBean获得ThreadInfo对象的完整列表,并查询它们以获得关于当前JVM上运行的线程的有用信息。

    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
     
    for(Long threadID : threadMXBean.getAllThreadIds()) {
        ThreadInfo info = threadMXBean.getThreadInfo(threadID);
    
        System.out.println("Thread name: " + info.getThreadName());
        System.out.println("Thread State: " + info.getThreadState());
    
        System.out.println(String.format("CPU time: %s ns", threadMXBean.getThreadCpuTime(threadID)));
    }
    

    首先调用getAllThreadIds方法获取当前线程列表。然后对每个线程输出其线程名称和状态,最后输出线程占用CPU时间(以纳秒为单位)。

    3. 使用Profiler监控系统

    这里需要提醒下,一般无需代码进行监控。Java Profilers密切监控jvm的关键指标并进行实时分析。从Java6开始自带的VisualVM工具功能很强大,其他一些IDE也包括相应插件实现相同功能。

    4. 总结

    本文我介绍Java api 如何监控系统关键指标,磁盘、内存以及线程使用情况,主要使用File、ManagmentFactory类获取相关信息。

    展开全文
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...
  • 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印 util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,...
  • java开源包1

    千次下载 热门讨论 2013-06-28 09:14:34
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包12

    热门讨论 2013-06-28 10:14:45
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • Java资源包01

    2016-08-31 09:16:25
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包101

    2016-07-13 10:11:08
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包11

    热门讨论 2013-06-28 10:10:38
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包2

    热门讨论 2013-06-28 09:17:39
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包3

    热门讨论 2013-06-28 09:20:52
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包6

    热门讨论 2013-06-28 09:48:32
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包5

    热门讨论 2013-06-28 09:38:46
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包10

    热门讨论 2013-06-28 10:06:40
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包4

    热门讨论 2013-06-28 09:26:54
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包8

    热门讨论 2013-06-28 09:55:26
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包9

    热门讨论 2013-06-28 09:58:55
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包7

    热门讨论 2013-06-28 09:52:16
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印 util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,...
  • 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印 util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,...
  • Java经典编程300例(code)

    千次下载 热门讨论 2013-01-09 10:26:53
    实例132 以树结构显示文件路径 193 实例133 查找替换文本文件内容 194 实例134 设置Windows系统的文件 属性 195 实例135 文件批量重命名 196 实例136 快速批量移动文件 197 实例137 删除文件夹中的.tmp文件 198 实例...
  • Thinking.In.Java

    2012-03-21 22:35:53
    除此之外,本节还要探讨如何获取一个对象、对其进行“流式”加工(使其能置入磁盘或通过网络传送)以及重新构建它等等。这些操作在Java的1.1版中都可以自动完成。另外,我们也要讨论Java 1.1的压缩库,它将用在Java...
  • 除此之外,本节还要探讨如何获取一个对象、对其进行“流式”加工(使其能置入磁盘或通过网络传送)以及重新构建它等等。这些操作在Java的1.1版中都可以自动完成。另外,我们也要讨论Java 1.1的压缩库,它将用在Java...
  • 除此之外,本节还要探讨如何获取一个对象、对其进行“流式”加工(使其能置入磁盘或通过网络传送)以及重新构建它等等。这些操作在Java的1.1版中都可以自动完成。另外,我们也要讨论Java 1.1的压缩库,它将用在Java...

空空如也

空空如也

1 2 3 4
收藏数 63
精华内容 25
关键字:

java获取磁盘内文件路径

java 订阅