zoukankan      html  css  js  c++  java
  • java基础>I/O

    IO操作作为整个JAVA中最复杂的开发包,但是要想跨过此部分,就必须对面向对象的基本概念非常的熟悉,对于抽象类也要熟悉。

    根据实例化子类的不同,完成的功能也不同。这句话就是IO操作的核心。

    整个IO包中实际上需要的就是五个类和一个接口:FileOutputStreamInputStreamWriterReaderSerializable

       所有的类和接口基本上都在java.io包中定义的。

       在IO操作记住:输出的时候使用PrintStream,输入的时候使用Scanner。

    一、File类

     File类的构造:publicFile(String pathname),在建立File对象的时候需要指定一个路径。

    现在要想创建一个文件,可以使用方法:public booleancreateNewFile() throwsIOException

    import java.io.File;
    
    public class FileDemo01 {
    
        public  static void main(String[] args)throws Exception {
    
            File file = new File("d:\\temp.txt");// 指定要操作的文件路径
    
            file.createNewFile();
    
        }
    
    }
    

    既然可以创建文件,那肯定也可以删除:public boolean delete()

    但是如果要想删除文件,则肯定要判断文件是否存在:public boolean  exists()

     那么下面完成这样的一个程序:如果文件存在,则删除掉,如果文件不存在,则创建新的。

    import java.io.File;
    
    public  class FileDemo01 {
    
        public static void main(String[] args)throws Exception {
    
            File file = new File("d:\\temp.txt");// 指定要操作的文件路径
    
            if (file.exists()) {
    
                file.delete(); // 删除文件
    
            } else {
    
                file.createNewFile();// 创建新文件
    
            }
    
        }
    
    }
    

    但是在创建和删除文件的时候发现会出现延迟的问题,因为JAVA运行机制是运行在JVM上,由JVM进行OS的具体的适应,所以中间存在延迟,而且本程序也有问题,在Java的最大特点是可移植性,但是在不同的操作系统中路径的分割符肯定是不一样的:

                       · windows中使用“\”

                       · linux中使用“/”

    那么要想解决这样的问题,就必须观察File类定义的常量:public static final String separator

    separator是一个常量,按照常量的命名要求肯定全部的字母都要大写:SEPARATOR。这些都是由于Java发展的历史原因所造成的问题。

    File file = new File("d:" + File.separator + "temp.txt");// 指定要操作的文件路径
    

    由于在给定文件的路径上有可能给出的是一个文件,也有可能给出的是一个文件夹,那么为了判断,在File类中提供了以下的两个方法:

                       ·判断是否是文件:         public  boolean  isFile()

                       ·判断是否是文件夹:     public  boolean  isDirectory()

    范例:判断类型

    import java.io.File;
    
    public  class FileDemo02 {
    
        public  static  void main(String[] args)throws Exception {
    
            File file1 = new File("d:" + File.separator + "temp.txt");// 指定要操作的文件路径
    
            File file2 = new File("d:" + File.separator + "testjava");// 指定要操作的文件路径
    
            System.out.println(file1.isFile());
    
            System.out.println(file2.isDirectory());
    
        }
    
    }
    

    在File类的操作中可以通过代码列出一个文件夹之中的完整内容,方法如下:

                       ·列出文件或文件夹的名称:public String[] list()

                       ·列出完整的路径,而且返回的是File类的对象:public   File[] listFiles()

    范例:使用list()方法

    import java.io.File;
    
    public  class FileDemo03 {
    
        public  static  void main(String[] args)throws Exception {
    
            File file = new File("d:" + File.separator + "testjava");// 指定要操作的文件路径
    
            if (file.isDirectory()) {// 如果是文件夹,则列出内容
    
                String list[] = file.list();// 列出全部的内容
    
                for (int x = 0; x < list.length; x++) {
    
                    System.out.println(list[x]);
    
                }}}}
    

    范例:使用listFiles()完成列表

    import java.io.File;
    
    public  class FileDemo03 {
    
        public  static   void main(String[] args)throws Exception {
    
            File file = new File("d:" + File.separator + "testjava");// 指定要操作的文件路径
    
            if (file.isDirectory()) {// 如果是文件夹,则列出内容
    
                File list[] =  file.listFiles() ;   // 列出全部内容
    
                for (int x = 0; x < list.length; x++) {
    
                    System.out.println(list[x]);
    
                }}}}
    

    使用listFiles()方法输出的时候可以输出一个完整的路径,而且返回的是File类的对象,可以进行更多的操作。

    import java.io.File;
    
    publicclass FileDemo03 {
    
        public  static  void main(String[] args)throws Exception {
    
            File file = new File("d:" + File.separator + "testjava");// 指定要操作的文件路径
    
            if (file.isDirectory()) {// 如果是文件夹,则列出内容
    
                File list[] = file.listFiles() ;   // 列出全部内容
    
                for (int x = 0; x < list.length; x++) {
    
                    System.out.println(list[x] +" --> " +  list[x].length());
    
                }}}}
    

    思考题:

    现在要求输出一个给定目录中的全部文件的路径。

    本程序肯定只能依靠递归的操作完成,因为在一个给定的路径下有可能还是文件夹,那么如果是文件夹的话则肯定要继续列出,重复判断。

    import java.io.File;
    
    public  class ListFileDemo {
    
        public  static  void main(String[] args) {
    
            File file = new File("D:" + File.separator);
    
            list(file);
    
        }
    
        public  static  void list(File file) {
    
            if (file.isDirectory()) {// 如果是文件夹,则继续列出
    
                File f[] = file.listFiles();
    
                if (f !=null) {// 文件夹的内容已经列出
    
                    for (int x = 0; x < f.length; x++) {
    
                        list(f[x]);// 继续列出每一个内容
    
                    }
    
                }
    
            }
    
            System.out.println(file);
    
        }
    
    }
    

    二、字节流与字符流

             File类本身是与文件操作有关,但是如果要想操作内容则必须使用字节流或字符流完成,但是不管是使用何种的输入输出流,其基本的操作原理是一样的(以文件流为准)

                      1  使用File类找到一个文件

                      2  通过字节流或字符流的子类进行对象的实例化

                      3  进行读或写的操作

                      4  关闭字节或字符流

          由于流的操作属于资源操作,所以在操作的最后一定要关闭以释放资源。

          操作流有以下几个:

                       ·字节流:OutputStream、InputStream

                       ·字符流:Writer、Reader

    2.1、字节输出流

    字节输出流使用的是OutputStream,此类定义如下:

    public abstract  class OutputStream extends Object implements Closeable, Flushable

    本类是一个抽象类,根据面向对象的概念,要通过子类进行对象的实例化操作。

    在此类中定义了如下的几个常用方法:

    public abstract class OutputStream extends Object implements Closeable, Flushable 
    {
        public abstract void write(int b) throws IOException;  	//写入一个字节,抽象方法
        public void write(byte[] b) throws IOException     		//将缓冲区中的若干字节写入输出流
        public void flush() throws IOException {}         		//立即传输
        public void close() throws IOException {}         		//关闭输出流,空方法
    }
    

    但是要想为OutputStream实例化,且进行文件操作的话,就要使用FileOutputStream子类。

         ·构造:public FileOutputStream(File file) throwsFileNotFoundException

    范例:使用字节流进行输出,输出“HelloWorld”。

    import java.io.File;
    
    import java.io.FileOutputStream;
    
    import java.io.OutputStream;
    
    public class OutputStreamDemo01 {
    
        public  static  void main(String[] args)throws Exception {
    
            // 1、通过File找到一个文件
    
            File file = new File("d:" + File.separator + "temp.txt");
    
            // 2、实例化OutputStream对象
    
            OutputStream out = new FileOutputStream(file);
    
            String info = "Hello  World!!!"; //要输出的字符串
    
            byte data[] = info.getBytes();// 将字符串变为字节数组
    
            out.write(data); // 输出内容
    
            out.close();
    
        }
    
    }
    

    现在已经可以向文件中输出内容了,但是此时程序每执行一次,实际上都会输出,但是属于覆盖的操作,如果要想在文件的尾部追加的话,则必须观察FileOutputStream类的另外一个构造:

                      ·追加:public FileOutputStream(File file,boolean append) throwsFileNotFoundException

                       如果需要在追加的上面加入换行的话,使用“\r\n”。

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.OutputStream;
    public class OutputStreamDemo01 {
    	public static void main(String[] args) throws Exception {
    		// 1、通过File找到一个文件
    		File file = new File("d:" + File.separator + "temp.txt");
    		// 2、实例化OutputStream对象
    		OutputStream out = new FileOutputStream(file, true); // 追加
    		String info = "\r\nHello World!!!"; // 要输出的字符串
    		byte data[] = info.getBytes(); // 将字符串变为字节数组
    		out.write(data); // 输出内容
    		out.close();
    	}
    }
    

    2.2、字节输入流

     程序中可以使用OutputStream进行输出的操作,也可以使用InputStream完成输入的操作,此类定义如下:

    public abstract class InputStream extends Object implements Closeable 
    {
        public abstract int read() throws IOException;   		//返回读取的一个字节,抽象方法
        public int read(byte[] b) throws IOException             //从输入流中读取若干字节到指定缓冲区,返回实际读取的字节数
        public void close() throws IOException {}       			//关闭输入流,空方法
    }
    

    类依然是一个抽象类,肯定要使用子类完成,如果是文件输入,使用FileInputStream类。

    如果要读,则肯定需要一个数组,数组肯定要首先开辟好大小,用于接收内容。

    但是,与OutputStream类似,要读取就要观察FileInputStream类的构造方法:

    ·构造:public FileInputStream(File file) throwsFileNotFoundException

    import java.io.File;
    
    import java.io.FileInputStream;
    
    import java.io.InputStream;
    
    public class InputStreamDemo01 {
    
        public  static  void main(String[] args)throws Exception {
    
            File file = new File("d:" + File.separator + "temp.txt");
    
            InputStream input = new FileInputStream(file);
    
            byte data[] =new byte[1024];// 开辟一个空间
    
            int len = input.read(data);// 接收输入流的内容
    
            System.out.println("内容是:(" + new String(data, 0, len) +")");
    
        }
    
    }
    

    以上的代码属于一次性全部读取,但是在InputStream类中也可以每次读取一个字节。

    import java.io.File;
    
    import java.io.FileInputStream;
    
    import java.io.InputStream;
    
    public class InputStreamDemo02 {
    
        public   static   void main(String[] args)throws Exception {
    
            File file = new File("d:" + File.separator + "temp.txt");
    
            InputStream input = new FileInputStream(file);
    
            byte data[] =new  byte[1024];// 开辟一个空间
    
            int len = 0;// 记录读取的长度
    
            int temp = 0;
    
            do {
    
                temp = input.read();// 读取一个字节
    
                if (temp != -1) {// 如果不为-1表示内容可以增加
    
                    data[len++] = (byte) temp;// 保存在字节数组中
    
                }
    
            } while (temp != -1);// 如果不是-1表示还有内容可以读
    
            System.out.println("内容是:(" + new String(data, 0, len) +")");
    
        }
    
    }
    

    但是以上的读取方式在开发中会变成另外一种代码形式:

    int temp = 0;
    
            while ((temp = input.read()) != -1) {
    
                data[len++] = (byte) temp;
    
            }
    

     2.3、字符输出流

    Writer属于字符输出流,Writer类也是一个抽象类,既然要操作文件,肯定使用FileWriter。

    import java.io.File;
    
    import java.io.FileWriter;
    
    import java.io.Writer;
    
    public  class WriterDemo01 {
    
        public   static  void main(String[] args)throws Exception {
    
            File file = new File("d:" + File.separator + "temp.txt");
    
            Writer out = new FileWriter(file);
    
            out.write("Hello  World");// 直接输出字符串
    
            out.close() ;
    
        }
    
    }
    

    2.4、字符输入流

     Reader也肯定是一个抽象类,要输入文件使用FileReader。

    import java.io.File;
    
    import java.io.FileReader;
    
    import java.io.Reader;
    
    public  class ReaderDemo01 {
    
        public  static  void main(String[] args)throws Exception {
    
            File file = new File("d:" + File.separator + "temp.txt");
    
            Reader read = new FileReader(file);
    
            char data[] =new  char[1024];
    
            int len = read.read(data);
    
            System.out.println(new String(data, 0, len));
    
        }
    
    }
    

    2.5、字节流和字符流的区别

    微笑Java 流在处理上分为字符流和字节流。字符流处理的单元为2个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。Java 内用 Unicode 编码存储字符,字符流处理类负责将外部的其他编码的字符流和 java 内 Unicode 字符流之间的转换。而类 InputStreamReader 和 OutputStreamWriter 处理字符流和字节流的转换。字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。

     微笑字节流和字符流在使用上的代码结构都是非常类似的,但是其内部本身也是有区别的,因为在进行字符流操作的时候会使用到缓冲区,而字节流操作的时候是不会使用到缓冲区的。在输出的时候,OutputStream类即使最后没有关闭内容也可以输出。但是如果是Writer的话,则如果不关闭,最后一条内容是无法输出的,因为所有的内容都是保存在了缓冲区之中,每当调用了close()方法就意味着清空缓冲区了。那么可以证明字符流确实使用了缓冲区。如果现在字符流即使不关闭也可以完成输出的话,则必须强制性清空缓冲区:

    方法:public void flush()throws IOException

    字节流不关闭,但是文件中也依然存在了输出的内容,证明字节流是直接操作文件本身的。

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.OutputStream;
    
    public class OutputStreamDemo05 {
    	public static void main(String[] args) throws Exception { // 异常抛出, 不处理
    	// 第1步:使用File类找到一个文件
    		File f = new File("d:" + File.separator + "test.txt"); // 声明File 对象
    		// 第2步:通过子类实例化父类对象
    		OutputStream out = null;
    		// 准备好一个输出的对象
    		out = new FileOutputStream(f);
    		// 通过对象多态性进行实例化
    		// 第3步:进行写操作
    		String str = "Hello World!!!";
    		// 准备一个字符串
    		byte b[] = str.getBytes();
    		// 字符串转byte数组
    		out.write(b);
    		// 将内容输出
    		// 第4步:关闭输出流
    		// out.close();
    		// 此时没有关闭
    	}
    }


    字符流不关闭

    import java.io.File;
    import java.io.FileWriter;
    import java.io.Writer;
    
    public class WriterDemo03 {
    	public static void main(String[] args) throws Exception { // 异常抛出, 不处理
    		// 第1步:使用File类找到一个文件
    		File f = new File("d:" + File.separator + "test.txt");// 声明File 对象
    		// 第2步:通过子类实例化父类对象
    		Writer out = null;
    		// 准备好一个输出的对象
    		out = new FileWriter(f);
    		// 通过对象多态性进行实例化
    		// 第3步:进行写操作
    		String str = "Hello World!!!";
    		// 准备一个字符串
    		out.write(str);
    		// 将内容输出
    		// 第4步:关闭输出流
    		// out.close();
    		// 此时没有关闭
    	}
    }

    程序运行后会发现文件中没有任何内容,这是因为字符流操作时使用了缓冲区,而在关闭字符流时会强制性地将缓冲区中的内容进行输出,但是如果程序没有关闭,则缓冲区中的内容是无法输出的,所以得出结论:字符流使用了缓冲区,而字节流没有使用缓冲区。

    两者相比,肯定使用字节流更加的方便,而且在程序中像图片、MP3等都是采用字节的方式的保存,那么肯定字节流会比字符流使用的更广泛。但是需要说明的是,如果要是想操作中文的话,字符流肯定是最好使的。

    2.6、例子:文件拷贝

             现在要求完成一个Copy程序,完全模仿DOS中的拷贝命令。

             命令的运行形式,可以通过初始化参数的方式设置两个路径

                       ·形式:java Copy源文件路径目标文件路径

             本程序完成有两个思路:

                       ·思路一:将所有的内容全部读取进来,之后一次性保存

                       ·思路二:边读边写

             而且要进行读取的时候还要判断源文件是否存在。

    import java.io.File;
    
    import java.io.FileInputStream;
    
    import java.io.FileOutputStream;
    
    import java.io.InputStream;
    
    import java.io.OutputStream;
    
    public class Copy {
    
        public  static  void main(String[] args)throws Exception {
    
            if (args.length != 2) {
    
                System.out.println("语法命令不正确!");
    
                System.exit(1);
    
            }
    
            File file1 = new File(args[0]);
    
            if (file1.exists()) {// 如果源文件存在
    
                File file2 = new File(args[1]);
    
                InputStream input = new FileInputStream(file1);
    
                OutputStream output =new FileOutputStream(file2);
    
                int temp = 0;
    
                while ((temp = input.read()) != -1) {// 边读边写
    
                    output.write(temp);// 输出
    
                }
    
                input.close();
    
                output.close();
    
                System.out.println("文件拷贝完成。");
    
            }
    
        }
    
    }
    

    三、内存操作流

     之前的文件操作流是以文件的输入输出为主的,但是如果现在将输入输出的位置一改变,改变成了内存,那么就称为内存操作流。使用ByteArrayInputStream完成内存的输入操作,而使用ByteArrayOutputStream完成内存的输出操作,但是一定要注意的是,现在的输入和输出都是以内存为标准的。

         ByteArrayInputStream构造:public ByteArrayInputStream(byte[] buf)

    import java.io.ByteArrayInputStream;
    
    import java.io.ByteArrayOutputStream;
    
    import java.io.InputStream;
    
    import java.io.OutputStream;
    
    public  class ByteArrayDemo {
    
        public  static  void main(String[] args)throws Exception {
    
            String info = "helloworld";
    
            InputStream input = new ByteArrayInputStream(info.getBytes());
    
            OutputStream output = new ByteArrayOutputStream();
    
            int temp = 0;
    
            while ((temp = input.read()) != -1) {
    
                output.write(Character.toUpperCase((char) temp));
    
            }
    
            String str = output.toString(); // 取出内容
    
            input.close() ;
    
            output.close() ;
    
            System.out.println(str) ;
    
        }
    
    }
    

    现在虽然完成了内存的操作,但是可以发现现在的IO都是从内存中,也就是说可以将内存当作一个临时的文件进行操作,所以内存操作流一般在产生临时文件内容的时候使用

    四、打印流

    思考:如果现在要想完成一个字符串或者是boolean型或者是字符型的数据输出使用OutputStream是否方便?

    肯定是不方便的,因为OutputStream中只能操作字节数据,所以其他的数据类型很难操作,那么在Java的IO包中为了解决这种问题增加了两种类:PrintStream、PrintWriter。

    4.1、 PrintStream

             观察PrintStream类的构造:public PrintStream(OutputStream out)

             虽然PrintStream是OutputStream的子类,但是在实例化的时候依然需要一个OutputStream的对象。

             在PrintStream中定义了一系列的输出操作,可以方便的完成输出,那么这种设计思路就是装饰设计

    import java.io.File;
    
    import java.io.FileOutputStream;
    
    import java.io.PrintStream;
    
    public class PrintStreamDemo01 {
    
        public  static  void main(String[] args)throws Exception {
    
            PrintStream out = new PrintStream(new FileOutputStream(new File("d:"
    
                    + File.separator +"test.txt")));
    
            out.print(1 + " +  " + 1 + " = ");
    
            out.println(1 + 1);
    
            out.println("Hello World!!!") ;
    
        }
    
    }
    

    在开发中由于PrintStream较为好用,所以只要是输出就使用打印流完成。一些数据的表示格式:%d、%f、%s

    import java.io.File;
    
    import java.io.FileOutputStream;
    
    import java.io.PrintStream;
    
    public  class PrintStreamDemo02 {
    
        public  static  void main(String[] args)throws Exception {
    
            PrintStream out = new PrintStream(new FileOutputStream(new File("d:" + File.separator +"test.txt")));
    
            String name = "张三";
    
            int age = 30;
    
            float score = 90.89765f;
    
            out.printf("姓名:%s,年龄:%d,成绩:%5.2f", name, age, score);
    
        }
    
    }
    

    4.2、PrintWriter

    PrintStream是OutputStream的子类,PrintWriter是Writer的子类,两者处于对等的位置上,PrintWriter是一种过滤流,也叫处理流。也就是能对字节流和字符流进行处理,所以它会有一下的构造方法。

    PrintWriter(OutputStream out)  根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。

    PrintWriter(Writer out)        创建不带自动行刷新的新 PrintWriter

    然后PrintWriter能够直接对文件操作,所以还有这两种构造方法:

    PrintWriter(File file)        使用指定文件创建不具有自动行刷新的新 PrintWriter。

    PrintWriter(String fileName)  创建具有指定文件名称且不带自动行刷新的新 PrintWrite

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.io.FileWriter;
    import java.io.File;
    
    public class PrintWriterDemo {
    
    	public static void main(String[] args) {
    		PrintWriter pw = null;
    		String name = "wsz";
    		int age = 22;
    		float score = 32.5f;
    		char sex = '男';
    		try {
    			pw = new PrintWriter(new FileWriter(new File("e:\\file.txt")), true);
    			pw.printf("姓名:%s;年龄:%d;性别:%c;分数:%5.2f;", name, age, sex, score);
    			pw.println();
    			pw.println("多多指教");
    			pw.write(name.toCharArray());
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally {
    			pw.close();
    		}
    	}
    }

    4.3、两者区别

    PrintStream是字节流,它有处理byte的方法,write(int)和write(byte[],int,int);PrintWriter是字符流,它没有处理byte的方法。PrintStream和PrintWriter的auto flushing机制有点不同,前者在输出byte数组、调用println方法、输出换行符或者byte值10(即\n)时自动调用flush方法,后者仅在调用println方法时发生auto flushing。

    五、System类对IO的支持

             在System类中定义了以下的三个常量:

                       ·错误输出:public static final PrintStream err

                       ·屏幕输出:public static final PrintStream out

                       ·键盘输入:public static final  InputStream  in

    5.1、错误输出

    System.err表示的是错误的输出,此类型也属于PrintStream类型。

    public  class SystemErrDemo {
    
        public  static  void main(String[] args) {
    
            try {
    
                Integer.parseInt("A");
    
            } catch (NumberFormatException e) {
    
                System.err.println(e);
    
            }
    
        }
    
    }
    

    使用System.err和System.out的输出是完全一样的,但是在Eclipse中System.err的输出会使用红色表示。两个的区别只是人为的增加的区别,System.err一般是不希望用户看见的错误,而System.out是希望用户看见的错误。

    5.2、屏幕输出

    System.out属于屏幕输出的操作,对应着显示器,但是可以通过System.out为OutputStream实例化。

    import java.io.OutputStream;
    
    public  class SystemOutDemo {
    
        public  static  void main(String[] args)throws Exception {
    
            OutputStream out = System.out ;
    
            out.write("hello  world".getBytes()) ;
    
        }
    
    }
    

    5.3、键盘输入

     一般的语言中都存在着键盘输入数据的操作,在Java中也有,只是一般来讲这种操作不是现成的,而且必须依靠IO流的操作才能完成,输入靠的是System.in。

    import java.io.InputStream;
    
    public  class SystemInDemo {
    
        public static void main(String[] args)throws Exception {
    
            InputStream input = System.in;// 可以由键盘输入
    
            byte data[] =new byte[1024];
    
            System.out.print("请输入内容:");
    
            int len = input.read(data);
    
            System.out.println("输入的内容是:" + new String(data, 0, len));
    
        }
    
    }
    

    此时已经完成了内容的输入,但是本程序有问题,因为现在所有的输入内容都是保存在了data这个字节数组之中,如果现在输入的内容的长度大于数组中的长度的话,则超出的部分无法接收。

     这种操作出现问题的主要原因是一开始的数组大小限制了长度,那么如果现在没有长度限制呢?

    import java.io.InputStream;
    
    public class SystemInDemo {
    
        public static  void main(String[] args)throws Exception {
    
            InputStream input = System.in;// 可以由键盘输入
    
            StringBuffer buf = new StringBuffer();
    
            System.out.print("请输入内容:");
    
            int temp = 0;
    
            while ((temp = input.read()) != -1) {
    
                char c = (char) temp;
    
                if (c =='\n') {
    
                    break ;
    
                }
    
                buf.append(c);
    
            }
    
            System.out.println("输入的内容是:" + buf);
    
        }
    
    }
    

     这种输入现在只能适合于英文环境上,因为是按照每一个字节的方式读取的,而一个中文是两个字节。

    所以,如果要想彻底的解决问题,最好的做法是,将所有的输入内容暂时存放到一个缓冲区之中,之后从缓冲区里一次性将内容全部读取回来。

    六、BufferedReader

             BufferedReader的主要功能是用于缓冲区读取的,但是有一点,从类的定义上可以发现,此类属于字符输入流,而System.in属于字节流,那么很明显,如果要想使用BufferedReader就需要将一个字节流变成字符流,为了解决这样的问题,在Java中提供了以下的两个转换类

             ·将输入的字节流变为字符流:InputStreamReader

            ·将输出的字符流变为字节流: OutputStreamWriter

             在BufferedReader类中提供了一个专门的读取操作:public String readLine() throws IOException

    import java.io.BufferedReader;
    
    import java.io.InputStreamReader;
    
    public class BufferDemo {
    
        public static void main(String[] args)throws Exception {
    
            BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
    
            System.out.print("请输入内容:");
    
            String info = null;// 用于接收输入的内容
    
            info = buf.readLine(); // 接收内容
    
            System.out.println(info);
    
        }
    
    }
    

    由于所有的内容都是从缓冲区一次性读取完成的,那么不会出现乱码问题。以上就是一个键盘输入的标准程序

    七、Scanner类

     在JDK 1.5之后为了方便输入,又增加了一个新的类:Scanner,此类并不是在java.io包中定义的,而是在java.util包中定义的public final class Scanner implements Iterator<String>,。使用Scanner可以方便的完成各种字节输入流的输入

    构造:public Scanner(InputStream source)

    Scanner类实现了Iterator接口,所以它有以下方法。

    boolean hasNext()方法

    Object next()方法

    void remove()方法

    useDelimiter()使用定界符的意思

    nextXxx()从流中读取一个Xxx并返回Xxx值。

    import java.util.Scanner;
    
    public  class ScannerDemo01 {
    
        public  static void main(String[] args) {
    
            Scanner scan = new Scanner(System.in);
    
            System.out.print("请输入内容:");
    
            if (scan.hasNext()) {// 现在有内容
    
                String str = scan.next();
    
                System.out.println("输入的内容是:" + str);
    
            }
    
        }
    
    }
    

    除了这种功能之外,使用Scanner也可以输入各种数据类型,例如:float。

    import java.util.Scanner;
    
    public  class ScannerDemo02 {
    
        public  static  void main(String[] args) {
    
            Scanner scan = new Scanner(System.in);
    
            System.out.print("请输入内容:");
    
            if (scan.hasNextInt()) {// 现在有内容
    
                int str = scan.nextInt();
    
                System.out.println("输入的内容是:" + str);
    
            }
    
        }
    
    }
    

    但是,如果要想进行其他数据格式验证的话,则就需要编写正则表达式完成了。

    import java.text.ParseException;
    
    import java.text.SimpleDateFormat;
    
    import java.util.Date;
    
    import java.util.Scanner;
    
    publicclass ScannerDemo03 {
    
        public  static  void main(String[] args) {
    
            Scanner scan = new Scanner(System.in);
    
            System.out.print("请输入日期:");
    
            if (scan.hasNext("\\d{4}-\\d{2}-\\d{2}")) {// 现在有内容
    
                String str = scan.next("\\d{4}-\\d{2}-\\d{2}");
    
                Date date = null;
    
                try {
    
                    date = new SimpleDateFormat("yyyy-MM-dd").parse(str);
    
                } catch (ParseException e) {
    
                    e.printStackTrace();
    
                }
    
                System.out.println(date);
    
            }
    
        }
    
    }
    

    使用Scanner类除了可以完成以上的输入之外,也可以从一个文件流中输入内容。

    import java.io.File;
    
    import java.io.FileInputStream;
    
    import java.util.Scanner;
    
    public  class ScannerFileDemo {
    
        public  static  void main(String[] args)throws Exception {
    
            Scanner scan = new Scanner(new FileInputStream(new File("d:"+ File.separator +"test.txt")));
    
            scan.useDelimiter("\n");// 将换行作为分隔符
    
            while (scan.hasNext()) {
    
                String str = scan.next();
    
                System.out.print(str);
    
            }
    
        }
    
    }
    

    八、Java IO 的一般使用原则 :

    一、按数据来源(去向)分类:

    1. 是文件: FileInputStream, FileOutputStream, ( 字节流 )FileReader, FileWriter( 字符 )
    2. 是 byte[] : ByteArrayInputStream, ByteArrayOutputStream( 字节流 )
    3. 是 Char[]: CharArrayReader, CharArrayWriter( 字符流 )
    4. 是 String: StringBufferInputStream, StringBufferOuputStream ( 字节流 )StringReader, StringWriter( 字符流 )
    5. 网络数据流: InputStream, OutputStream,( 字节流 ) Reader, Writer( 字符流 )

    二、按是否格式化输出分:
        要格式化输出: PrintStream, PrintWriter
    三、按是否要缓冲分:
        要缓冲:BufferedInputStream, BufferedOutputStream,(字节流) BufferedReader, BufferedWriter(字符流)
    四、按数据格式分:
        1 、二进制格式(只要不能确定是纯文本的) : InputStream, OutputStream 及其所有带 Stream 结束的子类
        2 、纯文本格式(含纯英文与汉字或其他编码方式); Reader, Writer 及其所有带 Reader, Writer 的子类
    五、按输入输出分:
        1 、输入: Reader, InputStream 类型的子类
        2 、输出: Writer, OutputStream 类型的子类
    六、特殊需要:
        1 、从 Stream 到 Reader,Writer 的转换类: InputStreamReader, OutputStreamWriter
        2 、对象输入输出: ObjectInputStream, ObjectOutputStream
        3 、进程间通信: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
        4 、合并输入: SequenceInputStream
        5 、更特殊的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader

    决定使用哪个类以及它的构造进程的一般准则如下(不考虑特殊需要):
    首先,考虑最原始的数据格式是什么: 原则四
    第二,是输入还是输出:原则五
    第三,是否需要转换流:原则六第1点
    第四,数据来源(去向)是什么:原则一
    第五,是否要缓冲:原则三 (特别注明:一定要注意的是 readLine() 是否有定义,有什么比 read, write 更特殊的输入或输出方法)
    第六,是否要格式化输出:原则二

    IO操作记住:输出的时候使用PrintStream,输入的时候使用Scanner

    总结

    1、使用File类可以操作文件,但是在编写文件分隔符的时候要注意使用File.separator

    2、字节流和字符流最大的区别在于字符流使用到了缓冲区操作,但是一般字节流使用较多

    3、内存流是所有的输入输出都在内存中完成:ByteArrayInputStream、ByteArrayOutputStream

    4、如果要输出内容可以使用PrintStream类方便的完成

    5、如果要输入内容可以使用Scanner类

    6、对象序列化http://blog.csdn.net/ncepustrong/article/details/8125025

  • 相关阅读:
    LeetCode 121. Best Time to Buy and Sell Stock
    LeetCode 221. Maximal Square
    LeetCode 152. Maximum Product Subarray
    LeetCode 53. Maximum Subarray
    LeetCode 91. Decode Ways
    LeetCode 64. Minimum Path Sum
    LeetCode 264. Ugly Number II
    LeetCode 263. Ugly Number
    LeetCode 50. Pow(x, n)
    LeetCode 279. Perfect Squares
  • 原文地址:https://www.cnblogs.com/xqzt/p/5637106.html
Copyright © 2011-2022 走看看