字节流

字符流:

  1. FileReader
  2. FileWriter
  3. BufferedReader
  4. BufferedWriter

字节流:

  1. FileInputStream
  2. FileOutputStream
  3. BufferedInputStream
  4. BufferedOutputStream

想要操作图片数据,这时就要用到字节流。

示例代码如下:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; public class FileOutputStreamDemo0 { public static void main(String[] args) throws IOException {
//writeFile();
//readFile(); //readFile_2(); readFile_3();
} public static void readFile_3() throws IOException {
FileInputStream fis = new FileInputStream("fos.txt"); //int num = fis.available(); byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区,不用在循环了。不过慎用!!! fis.read(buf); //System.out.println("num = " + num);
System.out.println(new String(buf)); fis.close();
} public static void readFile_2() throws IOException {
FileInputStream fis = new FileInputStream("fos.txt"); byte[] buf = new byte[1024];//还是建议使用1024的整数倍开辟字节数组 int len = 0; while((len = fis.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
} fis.close();
} public static void readFile() throws IOException {
FileInputStream fis = new FileInputStream("fos.txt"); int ch = 0; while((ch = fis.read()) != -1) {
System.out.println((char) ch);
} fis.close();
} public static void writeFile() throws IOException {
FileOutputStream fos = new FileOutputStream("fos.txt"); fos.write("abcde".getBytes()); fos.close();
} }

练习1:复制一个图片。

思路:

  1. 用字节读取流对象和图片关联。
  2. 用字节写入流对象创建一个图片文件,用于存储获取到的图片数据。
  3. 通过循环读写,完成数据的存储。
  4. 关闭资源。

代码:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; public class CopyPic { public static void main(String[] args) {
FileOutputStream fos = null;
FileInputStream fis = null; try {
fos = new FileOutputStream("E:\\MyJava\\workspace\\IO_Project\\Krystal.jpg");
fis = new FileInputStream("D:\\Krystal.jpg"); byte[] buf = new byte[1024]; int len = 0; while((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
} catch (IOException e) {
throw new RuntimeException("复制失败!");
} finally {
try {
if(fis != null)
fis.close();
} catch (IOException e) {
throw new RuntimeException("读取关闭失败!");
}
try {
if(fos != null)
fos.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭失败!");
}
}
} }

练习2:复制一个MP3文件。

通过缓冲区(BufferedOutputStream/BufferedInputStream),演示MP3的复制。

代码:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; public class CopyMp3 { public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
copy_2();
long end = System.currentTimeMillis();
System.out.println((end - start) + "毫秒");
}
/*
* 通过字节流的缓冲区完成复制
*/
public static void copy_1() throws IOException {
BufferedInputStream bufis = new BufferedInputStream(
new FileInputStream("E:\\KuGou\\Temp\\滨琦步 - 犬夜叉主题曲.mp3")); BufferedOutputStream bufos = new BufferedOutputStream(
new FileOutputStream("E:\\MyJava\\workspace\\IO_Project\\滨琦步 - 犬夜叉主题曲.mp3")); int by = 0; while((by = bufis.read()) != -1) {
bufos.write(by);
} bufis.close();
bufos.close();
} }

练习3:自定义一个类模拟BufferedInputStream,完成一个MP3文件的复制。

分析:

mp3是由二进制数据组成的:
11111111-1110000000000000000000101010110111010111010010110001 问题:自定义的myRead()函数为什么会返回int类型,而不直接返回byte类型呢?
分析:
byte: -1 ----> int: -1 11111111(-1)提升为11111111 11111111 11111111 11111111(-1)
11111111(-1)--->提升为一个int类型,那还不是-1吗?是-1的原因是因为在8个1前面补的都是1导致的。
那么我只要在前面补0,即可以保留原字节数据不变,又可以避免-1的出现。
怎么补0呢?
11111111 11111111 11111111 11111111
& 00000000 00000000 00000000 11111111
------------------------------------------
00000000 00000000 00000000 11111111 所以应把11111111(-1)提升为00000000 00000000 00000000 11111111(255),避免返回-1这种情况

代码:

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream; class MyBufferedInputStream {
private InputStream in;
private byte[] buf = new byte[1024 * 4];
private int pos = 0, count = 0; MyBufferedInputStream(InputStream in) {
this.in = in;
} /*
* 一次读一个字节,从缓冲区(字节数组)获取。
*/
public int myRead() throws IOException {
/*
* 通过in对象读取硬盘上数据,并存储到buf中。
*/
if(count == 0) {
count = in.read(buf);
if(count < 0)
return -1;
pos = 0;
byte b = buf[pos];
count--;
pos++;
return b & 255;
} else if(count > 0) {
byte b = buf[pos];
count--;
pos++;
return b & 0xff;
}
return -1;
} public void myClose() throws IOException {
in.close();
}
}
public class MyBufferedInputStreamDemo { public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
copy_2();
long end = System.currentTimeMillis();
System.out.println((end - start) + "毫秒");
} public static void copy_2() throws IOException {
MyBufferedInputStream bufis = new MyBufferedInputStream(
new FileInputStream("E:\\KuGou\\Temp\\滨琦步 - 犬夜叉主题曲.mp3")); BufferedOutputStream bufos = new BufferedOutputStream(
new FileOutputStream("E:\\MyJava\\workspace\\IO_Project\\滨琦步 - 犬夜叉主题曲_2.mp3")); int by = 0; //System.out.println("第一个字节:" + bufis.myRead());//第一个字节:-1,因为读到了连续的11111111 while((by = bufis.myRead()) != -1) {
bufos.write(by);
} bufis.myClose();
bufos.close();
} }

System类对IO的支持

读取键盘录入。

System.out:对应的是标准输出设备,控制台。

System.in:对应的是标准输入设备,键盘。

例,需求:通过键盘录入数据。当录入一行数据后,就将该行数据进行打印。如果录入的数据是over,那么录入停止。

代码:

import java.io.IOException;
import java.io.InputStream; public class ReadIn { public static void main(String[] args) throws IOException {
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while(true) {
int ch = in.read();
if(ch == '\r')
continue;
if(ch == '\n') {
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0, sb.length());//清空缓冲区
} else {
sb.append((char) ch);
} } //System.out.println('\r' + 0);//13
//System.out.println('\n' + 0);//
/*
int by = in.read();
int by1 = in.read();
int by2 = in.read(); System.out.println(by);
System.out.println(by1);
System.out.println(by2);
*/
}
}

通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。也就是readLine()方法。

能不能直接使用readLine()方法来完成键盘录入的一行数据的读取呢?

readLine()方法是字符流BufferedReader类中的方法,而键盘录入的read()方法是字节流InputStream的方法,那么能不能将字节流转成字符流,再使用字符流缓冲区的readLine()方法呢?

此时就需要用到转换流。

转换流:

  1. InputStreamReader字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集(GBK)
  2. OutputStreamWriter字符流通向字节流的桥梁:可使用指定的charset将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

上例优化之后的代码为:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter; public class TransStreamDemo0 { public static void main(String[] args) throws IOException {
/*
* 获取键盘录入对象。
*/
//InputStream in = System.in; /*
* 将字节流对象转成字符流对象,使用转换流——InputStreamReader
*/
//InputStreamReader isr = new InputStreamReader(in); /*
* 为了提高效率,将字符流进行缓冲区技术高效操作,使用BufferedReader
*/
//BufferedReader bufr = new BufferedReader(isr);
/*
* 简写格式,键盘录入最常见写法
*/
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in)); //OutputStream out = System.out;//屏幕输出
/*
* 字符流输出对象转换成字节流输出对象
*/
//OutputStreamWriter osw = new OutputStreamWriter(out); //BufferedWriter bufw = new BufferedWriter(osw);
/*
* 简写格式
*/
BufferedWriter bufw =
new BufferedWriter(new OutputStreamWriter(System.out)); String str = null;
while((str = bufr.readLine()) != null) {
if("over".equals(str))
break;
//System.out.println(str.toUpperCase());
bufw.write(str.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufw.close();//并没有写bufr.close();是因为此程序一结束掉,就给关闭了。
} }

流操作的基本规律

最痛苦的就是流对象有很多,不知道该用哪一个。

通过三个明确来完成:

  1、明确源和目的。

    源:输入流。InputStream Reader

    目的:输出流。OutputStream Writer

  2、操作的数据是否是纯文本。

    是:字符流。

    不是:字节流。

  3、当体系明确后,在明确要使用哪个具体的对象。

    通过设备来进行区分:

    源设备:内存、硬盘、键盘。

    目的设备:内存、硬盘、控制台。

例1、需求:将一个文本文件中的数据存储到另一个文件中。(复制文件)

  分析:

    源:因为是源,所以使用读取流。InputStream Reader

    是不是操作文本文件?

    是!这时就可以选择Reader,这样体系就明确了。

    接下来要明确要使用该体系中的那个对象?

    明确设备:硬盘上的一个文件。Reader体系中可以操作文件的对象是FileReader。

    是否需要提高效率?是!加入Reader体系中的缓冲区BufferedReader。

FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);

    目的:OutputStream Writer

    目的是否是纯文本?是!Writer。

    设备:硬盘上的一个文件。

    Writer体系中可以操作文件的对象是FileWriter。

    是否需要提高效率?是!加入Reader体系中的缓冲区BufferedWriter。

FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fr);

练习:将一个图片文件中的数据存储到另一个文件中。(复制文件)

代码:

/*
* 练习:将一个图片文件中的数据存储到另一个文件中。(复制文件)
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; public class test0 { public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
byte[] by = new byte[1024];
int len = 0;
try {
fis = new FileInputStream("d:\\Krystal.jpg");
bis = new BufferedInputStream(fis); fos = new FileOutputStream("d:\\java\\io123\\Krystal.jpg");
bos = new BufferedOutputStream(fos); while((len = bis.read(by)) != -1) {
bos.write(by, 0, len);
}
} catch (IOException e) {
throw new RuntimeException("图片复制失败!");
} finally {
try {
if(bis != null)
bis.close();
} catch (IOException e) {
throw new RuntimeException("关闭读取流失败!");
}
try {
if(bos != null)
bos.close();
} catch (IOException e) {
throw new RuntimeException("关闭写入流失败!");
}
}
} }

例2、需求:将键盘录入的数据保存到一个文件中。

  分析:

    这个需求中有源和目的都存在。那么分别分析

    源:InputStream Reader

    是不是纯文本?是!Reader

    设备:键盘。对应的对象是System.in。

    不是选择Reader吗?System.in对应的不是字节流吗?为了操作键盘的文本数据方便,转成字符流,按照字符串操作是最方便的。所以既然明确了Reader,那么就将System.in转换成字符流Reader。用到了Reader体系中的转换流,InputStreamReader

InputStreamReader isr = new InputStreamReader(System.in);

    需要提高效率吗?需要!BufferedReader 

BufferedReader bufr = new BufferedReader(isr);

    目的:OutputStream Writer

    是不是纯文本?是!Writer

    设备:硬盘上的一个文件。使用FileWriter。

FileWriter fw = new FileWriter("c.txt");

    需要提高效率吗?需要!BufferedWriter

BufferedWriter bufw = new BufferedWriter(fw);

  扩展一下,想要把录入的数据按照指定的编码表(UTF-8),将数据存到文件中,怎么办呢?

  分析:

    目的:OutputStream Writer

    是不是纯文本?是!Writer

    设备:硬盘上的一个文件。使用FileWriter。但是FileWriter是使用的默认编码表(GBK)

    但是存储时,需要加入指定的编码表(UTF-8),而指定的编码表只有转换流可以指定,所以要使用的对象是OutputStreamWriter。而该转换流对象要接收一个字节输出流,而且还可以操作文件的字节输出流,FileOutputStream。

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"), "UTF-8");

    需要提高效率吗?需要!BufferedWriter

BufferedWriter bufw = new BufferedWriter(osw);

  所以,记住,转换流什么时候使用?字符和字节之间的桥梁,通常涉及到字符编码转换时,需要用到转换流

练习:将一个文本数据打印在控制台上。

代码:

/*
* 练习:将一个文本数据打印在控制台上。
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter; public class test1 { public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
String line = null; try {
br = new BufferedReader(new FileReader("d:\\java\\ArrayTool.java"));
bw = new BufferedWriter(new OutputStreamWriter(System.out)); while((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
throw new RuntimeException("读取文件失败");
} finally {
try {
if(br != null)
br.close();
} catch (IOException e) {
throw new RuntimeException("读取流关闭失败");
}
try {
if(bw != null)
bw.close();
} catch (IOException e) {
throw new RuntimeException("写入流关闭失败");
}
} } }

异常的日志信息

 log4j:记录日志信息的一个工具。

示例代码如下:

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date; public class ExceptionInfo { public static void main(String[] args) { try {
int[] arr = new int[2];
System.out.println(arr[3]);
} catch (Exception e) {
try {
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d);
PrintStream ps = new PrintStream("exception.log");
//ps.write(d.toString().getBytes());
ps.println(s);
System.setOut(ps);
} catch (FileNotFoundException e1) {
throw new RuntimeException("日志文件创建失败!");
}
e.printStackTrace(System.out);
//e.printStackTrace(new PrintStream("ex.txt"));
}
} }

系统信息

示例代码如下:

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Properties; public class SystemInfo { public static void main(String[] args) throws FileNotFoundException {
Properties pro = System.getProperties();
//System.out.println(pro);
pro.list(new PrintStream("sysinfo.txt"));
} }

通过sysinfo.txt文本文件可以知道平台默认的字符集,即默认字符编码是GBK

Java IO(二)的更多相关文章

  1. 图解 Java IO : 二、FilenameFilter源码

    Writer      :BYSocket(泥沙砖瓦浆木匠) 微         博:BYSocket 豆         瓣:BYSocket FaceBook:BYSocket Twitter   ...

  2. java IO(二):字节流

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  3. Java IO(二) 之 InputStream

    源代码均以JDK1.8作为參考 前言: InputStream实现了两个接口Closeable和AutoCloseable: Closeable:JDK1.5中引入,Closeable接口中仅仅有一个 ...

  4. 系统学习 Java IO (二)----IO 异常处理

    目录:系统学习 Java IO---- 目录,概览 我们使用流后,需要正确关闭 Streams 和 Readers / Writers . 这是通过调用 close() 方法完成的,看看下面这段代码: ...

  5. Java IO(二)--RandomAccessFile基本使用

    RandomAccessFile: 翻译过来就是任意修改文件,可以从文件的任意位置进行修改,迅雷的下载就是通过多个线程同时读取下载文件.例如,把一个文件分为四 部分,四个线程同时下载,最后进行内容拼接 ...

  6. 系统学习 Java IO ---- 目录,概览

    Java IO 类的系统教程,原创.主要参考自英文教程 Java IO Tutorial 和 Java Doc. http://tutorials.jenkov.com/java-io/index.h ...

  7. Java IO详解(二)------流的分类

    一.根据流向分为输入流和输出流: 注意输入流和输出流是相对于程序而言的. 输出:把程序(内存)中的内容输出到磁盘.光盘等存储设备中      输入:读取外部数据(磁盘.光盘等存储设备的数据)到程序(内 ...

  8. Java IO学习笔记二

    Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...

  9. Java基础---IO(二)--File类、Properties类、打印流、序列流(合并流)

    第一讲     File类 一.概述 1.File类:文件和目录路径名的抽象表现形式 2.特点: 1)用来将文件或文件夹封装成对象 2)方便于对文件与文件夹的属性信息进行操作 3)File类的实例是不 ...

随机推荐

  1. ios 将Log日志重定向输出到文件中保存

    对于真机,日志没法保存,不好分析问题.所以有必要将日志保存到应用的Docunment目录下,并设置成共享文件,这样才能取出分析. 首先是日志输出,分为c的printf和标准的NSLog输出,print ...

  2. [转]KDE/QT与GNOME/GTK比较

    [转]KDE/QT与GNOME/GTK比较 http://www.cnblogs.com/itech/archive/2009/08/18/1548964.html 虽然在商业方面存在竞争,GNOME ...

  3. EF6 在原有数据库中使用 CodeFirst 总复习(二、新的需求,简单修改原有表)

    一.为当前实体模型启用数据迁移 基础搭建好了,也就是原有的数据库有了,原有数据库的实体对象也有了,但生成的上下文中并没有标记当前数据库是否已经存在,当前实体是否修改过(以前版本好像有标记的),所以,要 ...

  4. 0-N背包为题(动态规划算法)

    /****************0-N背包问题****************** * 有n个物体装入容量为c的背包,每一个物体有一个体积 * 和一个价值,所装入的物体体积之和不大于背包体积, * ...

  5. spring mvc官网下最新jar搭建框架-静态资源访问处理-注解-自动扫描

    1.从官网下载spring相关jar http://spring.io/projects 点击SPRING FRAMEWORK

  6. Scrum仪式之Sprint计划会议

    会议时间:4.15.晚八点 会议地点:基础教学楼二楼 会议进程 • 首先我们讨论了实验第一个Sprint1要实现的功能,我们的初期目标.•  然后我们进一步梳理了第一阶段的任务和需求.•  之后对任务 ...

  7. 【Merge Sorted Array】cpp

    题目: Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Not ...

  8. 用setTimeout 代替 setInterval实时拉取数据

    在开发中,我们常常碰到需要定时拉取网站数据,如: setInterval(function(){ $.ajax({ url: 'xx', success: function( response ){ ...

  9. Readhat Linux5.5 安装SVNService(经验总结)

    Subversion独立服务和与apache整合服务. 一 .Svn独立服务安装 操作系统: Redhat Linux5.5 安装包获取: 下载 http://subversion.tigris.or ...

  10. 在云服务器搭建WordPress博客(六)发布和管理文章

    <( ̄︶ ̄)↗[GO!] 发布文章是一个网站后台最重要的功能之一,WordPress的文章发布功能是比较强大的,系统简单地介绍一下. 访问后台 – 文章 – 写文章 ,就可以看到如下图所示的界面 ...