Java输入输出流


说明

  • 本文总结了上课Java老师的讲解,记录了一些经典的java用法
  • 本文篇幅较长,没有耐心与兴趣的朋友勿入

I/O流的概念

  • 流(stream

Java采用流的概念屏蔽了存储数据的起点和终点种类,文件、键盘、网络和其他设备都可以把它们抽象为流,通过流可以自由地控制文件、内存、I/O设备等数据的流向

  • 流的分类

    • 根据I/O流的流向可分为输入流(inputstream)和输出流(outputsteam
    • 当程序读取数据时,开启了一个通向起点数据源的输入流,这个起点可以是文件、内存、网络连接。
    • 当程序写入数据时,开启了一个通向目的地的输出流。
  • 读写数据的方法基本遵循步骤

    1. 打开一个流 (I/O流一旦被创建后,就会自动打开
    2. 读(写)信息
    3. 关闭流


I/O流的种类

  • 字节流(byte oriented stream

    • 字节流以8位的字节为基本处理单位
    • 字节流不能直接处理Unicode字符
  • 字符流(byte oritented stream)

    • 字符流以16位的字节为基本处理单位
    • 字符流处理的单元为16位的Unicode字符,由Java虚拟机将字节转化为16位的Unicode字符


适用范围

  • 字节流
  1. 所有文件的存储都是字节(byte)的存储,因此字节流可用于任何类型的对象,如音频文件、图片、歌曲
  • 字符流
  1. 处理多国语言,就得用字符流
  2. 字符流通常处理文本


详细

一、文件File类

  • 文件类的方法

File 类是 java.io 包中唯一代表磁盘文件本身的对象,也就是说,如果希望在程序中操作文件和目录,则都可以通过 File 类来完成。

File 类定义了一些方法来操作文件,如新建、删除、重命名文件和目录等。File 类不能访问文件内容本身,如果需要访问文件内容本身,则需要使用输入/输出流。

方法名称 说明
boolean canRead() 测试应用程序是否能从指定的文件中进行读取
boolean canWrite() 测试应用程序是否能写当前文件
boolean delete() 删除当前对象指定的文件
boolean exists() 测试当前 File 是否存在
String getAbsolutePath() 返回由该对象表示的文件的绝对路径名
String getName() 返回表示当前对象的文件名或路径名(如果是路径,则返回最后一级子路径名)
boolean createNewFile() 创建一个新的文件。
boolean isAbsolute() 当前 File 对象表示的文件是否为一个绝对路径名。
boolean isDirectory() 测试当前 File 对象表示的文件是否为一个路径
boolean isFile() 当前 File 对象表示的文件是否为一个“普通”文件
long lastModified() 返回当前 File 对象表示的文件最后修改的时间
long length() 返回当前 File 对象表示的文件长度
String[] list() 返回当前 File 对象指定的路径文件列表
String[] list(FilenameFilter) 返回当前 File 对象指定的目录中满足指定过滤器的文件列表
boolean mkdir() 创建一个目录,它的路径名由当前 File 对象指定
boolean mkdirs() 创建一个目录,它的路径名由当前 File 对象指定
boolean renameTo(File) 将当前 File 对象指定的文件更名为给定参数 File 指定的路径名
  • 文件类举例

(1)在磁盘上创建一个文件,先创建文件夹,再创建文件。

public class MyFileDemo {

  public static void main(String args[]) {

    String path = "d:"+File.separator+"filetest";

    File filePath = new File(path);

    if (filePath.exists()) {

      filePath.delete();

    }

    filePath.mkdir();

    File file = new File(path+File.separator+"test.txt");

    if (file.exists()) {

      file.delete();

    }

    try {

      file.createNewFile();

      System.out.println("创建文件成功!");

    } catch (IOException e) {

      e.printStackTrace();

    }

  }

}

(2)遍历一个文件夹

public class ListAllFile {
    
  public static void main(String[] args) {

    String path = "e://360Downloads";

    File file = new File(path);

    showAllFile(file);

  }

  private static void showAllFile(File file) {

    if (file.isDirectory()) {//如果是目录

      System.out.println("文件夹:" + file.getName());

      File[] listFiles = file.listFiles();//获取当前路径下的所有文件和目录,返回File对象数组

      for (File f : listFiles) {//将目录内的内容对象化并遍历

       showAllFile(f);

      }

    } 

    else if(file.isFile()) {//如果是文件

      System.out.println("文件:" + file.getName());

    }

  }

}

二、输入输出流

  • 实例:用字节流把数据写入文件和读到内存中。

public class InptutAndOutDemo {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String data="jiava计算机";
        File file=new File("D:"+File.separator+"test.txt");
        writeDataToFile(file,data);
        readFromFile(file);
    }
    private static void readFromFile(File file) {
        // TODO Auto-generated method stub
        InputStream inputStream=null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        int flen = (int) file.length();
        byte[] b = new byte[flen];
        int len =0;
        try {
             len = inputStream.read(b);
        }catch (IOException e1){
            e1.printStackTrace();
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println(len);
        System.out.print(new String(b));
    }

    private static void writeDataToFile(File file, String data)  {
        // TODO Auto-generated method stub
        OutputStream outputStream=null;
        try {
            outputStream=new FileOutputStream(file);
            outputStream.write(data.getBytes());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

三、字符输入输出流举例

字符流只能操作文本文件,不能操作图片,视频等非文本文件(因为是二进制存储的,要用字节流)

  • 字符输出流(Writer)

public abstract class Writer是用于写出字符流的所有类的超类,是一个抽象类,它定义了字节输出流的基本共性能方法

方法名称 说明
void write(int c) 写入单个字符
void write(char[] cbuf) 写入字符数组
abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分
void write(String str) 写入字符串
void write(String str, int off, int len) 写入字符串的某一部分
void flush() 刷新该流的缓冲
  • FileWriter类是写字符到文件的类,构造时使用系统默认的字符编码和默认字节缓冲区。
方法名称 说明
FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象
FileWriter(File file, boolean append) 根据给定的 File 对象构造一个 FileWriter 对象。其中append参数代表是否追加
FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象
FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象


  • 字符输入流

Reader 类是所有字符流输入类的父类,该类定义了许多方法,这些方法对所有子类都是有效的。

方法名及返回值类型 说明
int read() 从输入流中读取一个字符,并把它转换为 0~65535 的整数。如果返回 -1, 则表示 已经到了输入流的末尾。为了提高 I/O 操作的效率,建议尽量使用下面两种 read() 方法
int read(char[] cbuf) 从输入流中读取若干个字符,并把它们保存到参数 cbuf 指定的字符数组中。 该方 法返回读取的字符数,如果返回 -1,则表示已经到了输入流的末尾
int read(char[] cbuf,int off,int len) 从输入流中读取若干个字符,并把它们保存到参数 cbuf 指定的字符数组中。其中, off 指定在字符数组中开始保存数据的起始下标,len 指定读取的字符数。该方法返 回实际读取的字符数,如果返回 -1,则表示已经到了输入流的末尾

Java 提供了用来读取字符文件的便捷类——FileReader。该类的构造方法有如下两种重载形式。

方法名称 说明
FileReader(File file) 在给定要读取数据的文件的情况下创建一个新的 FileReader 对象。其中,file 表示要从中读取数据的文件
FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader 对象。其中,fileName 表示要从中读取数据的文件的名称,表示的是一个文件的完整路径

举例:

public class ReaderAndWriterDemo {
    public static void main(String[] args) throws IOException {
        String data="jiava计算机";
        File file=new File("D:"+File.separator+"test1.txt");
        Writer writer=new FileWriter(file,true);//追加方式
        writer.write("\r\n");
        writer.write("你好!\r\n");
        writer.write("我在学习!\r\n");
        writer.flush();
        writer.close();
        //读数据
        Reader reader=new FileReader(file);
        int len=(int)file.length();
        char myChar[]=new char[len];
        int rlen = reader.read(myChar);
        System.out.println(rlen);
        System.out.println(new String(myChar));
        reader.close();
    }
}

四、Java缓冲输入输出流

为什么要缓冲输入输出流?由于I/O的速度和CPU的速度不匹配,导致文件的读取较慢。所以通过缓存,一次性将大量的数据刷入内存或者保存在本地上。提高文件的访问效率。

字节缓冲流: BufferedInputStream , BufferedOutputStream

字符缓冲流: BufferedReader , BufferedWriter

  • 字节缓冲流的使用(复制文件)
public class CopyFileByBuffer {
public static void main(String[] args) {
        File sourceFile=new File("d:"+File.separator+"filetest"+File.separator+"xx.zip");
        File targetFile=new File("d:"+File.separator+"movie"+File.separator+"xx.zip");
        long startTime = System.currentTimeMillis();
        copyFileByBuffered(sourceFile,targetFile);
        long endTime = System.currentTimeMillis();
        System.out.println("缓冲流(默认缓冲区)复制时间:" + (endTime - startTime) + " 毫秒");
    }
    private static void copyFileByBuffered(File sourceFile, File targetFile) {
        int b;
        try {
           BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile),2048);
           BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(targetFile),2048);
           while((b=bis.read())!=-1) {
               bos.write(b);
           }
           bis.close();
           bos.flush();
           bos.close();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
    }
}
  • 字节缓冲流的使用(高效复制文件)
public class CopyFileByBufferMore {
    public static void main(String[] args) {
        File sourceFile=new File("d:"+File.separator+"filetest"+File.separator+"xx.zip");
        File targetFile=new File("d:"+File.separator+"movie"+File.separator+"xx.zip");
        long startTime = System.currentTimeMillis();
        copyFileByBuffered(sourceFile,targetFile);
        long endTime = System.currentTimeMillis();
        System.out.println("缓冲流(默认缓冲区)复制时间:" + (endTime - startTime) + " 毫秒");
    }
    private static void copyFileByBuffered(File sourceFile, File targetFile) {
        int b;
        byte[] bytes=new byte[8*1024];
        try {
           BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile),2048);
           BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(targetFile),2048);
           while((b=bis.read(bytes))!=-1) {
               bos.write(bytes,0,b);
           }
           bis.close();
           bos.flush();
           bos.close();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
    }
}
  • 使用字符缓冲流逐行读取文件。创建Student类
public class ReadFileByBuffered {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
       List<Student> list=new ArrayList<Student>();
       File file=new File("d:"+File.separator+"filetest"+File.separator+"score.txt");
       try {
            BufferedReader br=new BufferedReader(new FileReader(file));
            String line = null;
            br.readLine();
            String score[]=new String[7];
            while((line=br.readLine())!=null) {
                score=line.split("\\s+");
                Student st=new Student();
                for(int i=0;i<score.length;i++) {
                    st.setId(score[0]);
                    st.setName(score[1]);
                    st.setMath(Integer.parseInt(score[2]));
                    st.setChinese(Integer.parseInt(score[3]));
                    st.setEnglish(Integer.parseInt(score[4]));
                    st.setTotal(st.getMath()+st.getChinese()+st.getEnglish());
                    st.setAverage(st.getTotal()/3.0f);
                }
                list.add(st);
            }
            br.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       for(Student st:list) {
           System.out.println(st.getId()+" "+"\t"+st.getName());
       }
    }
}

五、对象序列化与对象输入输出流

Java中要实现将对象保存起来持久化,需要让对象实现Serializable接口,这样就能将java对象用二进制流保存并恢复。

public class SaveObject {
    public static void main(String[] args) {
        File fileName=new File("d:\\filetest\\obj.txt") ;
        try {
            ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(fileName));
            User user=new User(1,"张三",18,"男");
            oos.writeObject(user);
             oos.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }  
        //读取对象流
        try {
            ObjectInputStream ois=new ObjectInputStream(new FileInputStream(fileName));
            try {
                User user1=(User)ois.readObject();
                System.out.println(user1.toString());
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }  
    }
}

六、RandomAccessFile 类

RandomAccessFile 类支持 "随机访问" 的方式,程序可以直接跳到文件的任意地方来读、写文件。支持文件追加。RandomAccessFile 类支持字节和字符流。

方法 功能描述
long length() 返回文件长度
void seek(long pos) 移动文件位置指示器,pos 指定从文件开头的偏离字节数
int skipBytes(int n) 跳过 n 个字节,返回数为实际跳过的字节数
int read() 从文件中读取一个字节,字节的高 24 位为 0,若遇到文件结尾,返回-1
final byte readByte() 从文件中读取带符号的字节值
final char readChar() 从文件中读取一个 Unicode 字符
final void writeChar(inte c) 写入一个字符,两个字节
final void writeBytes(String s) 写入个字符串

实例RandomAccessFile读写

private static void readFile(File file) {
        // TODO Auto-generated method stub
        try {
            RandomAccessFile raf=new RandomAccessFile(file, "r");
            String line=null;
            raf.seek(0);
            while((line=raf.readLine())!= null){
                System.out.println(new String(line.getBytes("ISO-8859-1"),"gb2312"));
            }
            raf.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    private static void writeFile(File file) {
        try {
            RandomAccessFile raf=new RandomAccessFile(file, "rw");
            long len=raf.length();
            raf.seek(len);//在文件尾部写行
            raf.write(("中午"+"\r\n").getBytes());;
            raf.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


public static void main(String[] args) {
        RandomAccessFile so=null;
        RandomAccessFile ta=null;
        try {
            so=new RandomAccessFile("src\\myfile\\360qudong.exe","r");
            ta=new RandomAccessFile("src\\myfile\\360qudong1.exe","rw");
            byte b[]=new byte[1024];
            int len;
            while((len=so.read(b))!=-1){
                ta.write(b,0,len);
            }
            System.out.println("0k");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            if(ta!=null){
                try {
                    ta.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(so!=null){
                try {
                    so.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }   
        }
    }
}


七、URL对象与输入输出流

URL全称是“统一资源定位”,表示的是网络上的某个文件。Java中URL类是用来操作网络中的资源文件。

  • URL类的构造方法:
序号 方法描述
1 public URL(String protocol, String host, int port, String file) throws MalformedURLException. 通过给定的参数(协议、主机名、端口号、文件名)创建URL。
2 public URL(String protocol, String host, String file) throws MalformedURLException 使用指定的协议、主机名、文件名创建URL,端口使用协议的默认端口。
3 public URL(String url) throws MalformedURLException 通过给定的URL字符串创建URL
4 public URL(URL context, String url) throws MalformedURLException 使用基地址和相对URL创建
  • URL类的方法

    URL类的方法很多,这里介绍openConnection()方法:

    public URLConnection openConnection() throws IOException: 打开一个URL连接,并返回一个HttpURLConnection对象。

  • HttpURLConnection对象的方法

    public InputStream getInputStream() throws IOException:返回URL的输入流,用于读取资源。

实例:程序下载网页中的图片

public static void main(String[] args) {
saveImage("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png");
    }
    private static void saveImage(String str) {
        URL url=null;
        HttpURLConnection conn=null;
        try {
            url=new URL(str);
            conn=(HttpURLConnection)url.openConnection();
            conn.connect();
            BufferedInputStream bis=new BufferedInputStream(conn.getInputStream());
            BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("d:\\ddd.png"));
            byte bt[]=new byte[1024];
            int size;
            while((size=bis.read(bt))!=-1) {
                bos.write(bt,0,size);
            }
            System.out.println("finsh");
            bos.flush();
            bos.close();
            bis.close();
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容