Java基础教程——字节流
IO流
水流 | 特点 |
---|---|
连续性 | 逝者如斯夫,不舍昼夜; |
方向性 | 一江春水向东流。水往低处流。百川东到海,何时复西归?少壮不努力,老大徒伤悲! |
源头尽头 | 唯有源头活水来;覆水难收 |
Java里的IO也有这样的特点。
IO:数据从硬盘流向内存(Input),或者从内存流向硬盘(Output)。
IO流分类:
按照流的流向来分:输入流、输出流。
|-输入流:读入内存。
|-输出流:写出到硬盘等设备。
按操作数据单元分:字节流、字符流
|-字节流:8位
|-字符流:16位
按流的角色分:节点流、处理流。
|-节点流:特定的IO设备(如硬盘),也叫低级流
|-处理流:经过封装的流,也叫高级流、包装流,可以消除不同节点流的差异(典型的装饰器模式)
Java的IO流有40多个类,高抽象层的基类有四个:
字节流 | 字符流 | |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
字节流
字节流:100100011010100010
可以操作所有文件,包括文本文件、视频、音频、压缩文件等等都可以用字节流读写。
两个重要的抽象类:
(1)抽象类 java.io.OutputStream,是输出字节流的所有类的超类
|--API方法摘要:
|--|--void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。
|--|--abstract void write(int b) 将指定的字节写入此输出流。
|--|--void close() 关闭此输出流并释放与此流有关的所有系统资源。
(2)抽象类 java.io.InputStream,是输入字节流的所有类的超类
|--API方法摘要:
|--|--abstract int read()从输入流中读取数据的下一个字节。
|--|--int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
|--|--void close() 关闭此输入流并释放与该流关联的所有系统资源。
FileOutputStream写文件
// 文件输出流。完整地说,是文件字节输出流。
public class FileOutputStream extends OutputStream
步骤:
1.创建流对象
2.调用write方法,把数据写入文件
3.释放资源
import java.io.*;
public class 文件字节输出流 {
public static void main(String[] args) {
File file = new File("文件字节输出流.txt"); // 创建文件对象
try {
// (1)构造:通过文件对象创建文件输出流对象
FileOutputStream fos = new FileOutputStream(file);
// (2)写入文件
// (2.1)write(int b) 将"单个字节"写入到文件中
for (int i = 49; i < 97; i++) {
fos.write(i);
fos.write(' ');
}
// (2.2)write(byte[] b) 将"字节数组"中的数据全部写入文件
byte[] buffer = "I Love Java,你呢?".getBytes();
fos.write(buffer);
// (3)关闭流
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
追加:
使用构造方法:FileOutputStream(File file, boolean append)
// 构造:通过文件对象创建文件输出流对象
// 附加第二个参数true,指定进行文件追加,默认为不追加
fos = new FileOutputStream(file, true);
回车换行:
CR(carriage return),回车,\r
LF(line feed),换行,\n
windows:\r\n
linux或unix:\n
mac:\r
FileInputStream读文件
public class FileInputStream extends InputStream
import java.io.*;
public class 文件字节输入流 {
static final int C_CONDITION = 2;
public static void main(String[] args) {
try {
File file = new File("testRead.dat"); // 创建文件对象
// 【1】创建输入流对象,相当于打开文件
FileInputStream fis = new FileInputStream(file);
if (C_CONDITION == 1) {
// 【2】.read():读取单个字节
for (int i = 0; i < file.length(); i++) {
// 循环读取"字节",转为字符输出,英文没问题
int read = fis.read();
char ch = (char) read;
System.out.print(ch);
}
System.out.println();
} else {
// 【2】.read(byte[] b):读取文件中的数据到字节数组
// 根据文件的字节长度创建字节数组
long len = file.length();
byte[] buf = new byte[(int) len];
fis.read(buf);
// 利用字节数组创建字符串
String str = new String(buf);
System.out.println(str);
}
// 【3】关闭流
fis.close();
} catch (FileNotFoundException fnfe) {
System.out.println("文件打开失败。");
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
复制文件
package ahjava.io;
import java.io.*;
public class 复制文件 {
public static void main(String[] args) {
字节流复制文件();
}
static void 字节流复制文件() {
File srcFile = new File("testRead.dat"); // 源文件对象
File destFile = new File("testCopy.java"); // 目标文件对象
if (destFile.exists()) {
// 判断目标文件是否存在,存在则删除
destFile.delete();
}
// 目标文件不存在才复制
try {
destFile.createNewFile();
// 创建文件输入/输出流对象
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
// 创建字节数组,作为临时缓冲
byte[] buf = new byte[128];
System.out.println("开始复制文件...");
int len = -1;
// 循环从文件输入流中读取数据
while ((len = fis.read(buf)) != -1) {
System.out.println(len);
// 写入到文件输出流中
fos.write(buf, 0, len);
}
System.out.println("文件复制成功!");
fis.close(); // 关闭流
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面的代码有哪些风险?
改进版:
static void 字节流复制文件2() {
// 1.close()提取到finally中
// 2.提取FilexxxStream对象
// 3.初始化(否则不准close)
// 4.close()时加判空语句
FileInputStream fis = null;
FileOutputStream fos = null;
File srcFile = new File("testRead.dat"); // 源文件对象
File destFile = new File("testCopy.java"); // 目标文件对象
if (destFile.exists()) {
// 判断目标文件是否存在,存在则删除
destFile.delete();
}
// 目标文件不存在才复制
try {
destFile.createNewFile();
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
// 创建字节数组,作为临时缓冲
byte[] buf = new byte[128];
System.out.println("开始复制文件...");
int len = -1;
// 循环从文件输入流中读取数据
while ((len = fis.read(buf)) != -1) {
System.out.println(len);
// 写入到文件输出流中
fos.write(buf, 0, len);
}
System.out.println("文件复制成功!");
// 关闭流
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
fis = null;
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
fos = null;
}
}
}
又臭又长!
Java 7异常处理写法:
try后面增加括号,其中定义流对象,该流对象仅在try中有效,执行完毕自动释放,不需要写finally。
try(流对象){
} catch (IOException e) {
}
具体代码如下:
static void 字节流复制文件3() {
File srcFile = new File("testRead.dat"); // 源文件对象
File destFile = new File("testCopy.java"); // 目标文件对象
if (destFile.exists()) {
// 判断目标文件是否存在,存在则删除
destFile.delete();
}
// try(流对象)
try (FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile)) {
destFile.createNewFile();
// 创建字节数组,作为临时缓冲
byte[] buf = new byte[128];
System.out.println("开始复制文件...");
int len = -1;
// 循环从文件输入流中读取数据
while ((len = fis.read(buf)) != -1) {
System.out.println(len);
// 写入到文件输出流中
fos.write(buf, 0, len);
}
System.out.println("文件复制成功!");
// 关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
*Java9异常处理写法
觉得try里的代码太繁琐,try()中可以引入外部的变量:
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
try (fis;fos){...}
// ↑ 理想状态,代码并不能这么写
然而,fis、fos本身需要抛异常,如果直接try...catch,这两个变量会变成另外的try中的局部变量;
如果把声明提取到try之外,try (fis;fos)又需要变量是final的
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try (fis;fos) {
CopyFile.java:20: 错误: 用作 try-with-resources 资源的变量 fis 既不是最终变量, 也不是实际上的最终变量
try (fis;fos) {
^
CopyFile.java:20: 错误: 用作 try-with-resources 资源的变量 fos 既不是最终变量, 也不是实际上的最终变量
try (fis;fos) {
所以,fis和fos需要往外抛出异常,外部调用的地方又需要捕获异常。比不用此功能还要麻烦。可运行代码如下:
import java.io.*;
public class CopyFile{
public static void main(String[] args) {
try {
copyJDK9();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
static void copyJDK9() throws FileNotFoundException {
File srcFile = new File("testRead.dat");
File destFile = new File("testCopy.java");
if (destFile.exists()) {
destFile.delete();
}
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
try (fis;fos) {
destFile.createNewFile();
byte[] buf = new byte[128];
System.out.println("start copy...");
int len = -1;
while ((len = fis.read(buf)) != -1) {
System.out.println(len);
fos.write(buf, 0, len);
}
System.out.println("success");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java基础教程——字节流的更多相关文章
- Java基础教程(25)--I/O
一.I/O流 I/O流表示输入源或输出目标.流可以表示许多不同类型的源和目标,例如磁盘文件.设备.其他程序等. 流支持许多不同类型的数据,包括字节.原始数据类型.字符和对象等.有些流只传递数据 ...
- Java基础教程(18)--继承
一.继承的概念 继承是面向对象中一个非常重要的概念,使用继承可以从逻辑和层次上更好地组织代码,大大提高代码的复用性.在Java中,继承可以使得子类具有父类的属性和方法或者重新定义.追加属性和方法. ...
- Java基础教程(12)--深入理解类
一.方法的返回值 当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...
- Java基础教程:注解
Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...
- Java基础教程:网络编程
Java基础教程:网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个s ...
- Java基础教程(5)--变量
一.变量 1.变量的定义 正如上一篇教程<Java基础教程(4)--面向对象概念>中介绍的那样,对象将它的状态存在域中.但是你可能仍然有一些疑问,例如:命名一个域的规则和惯例是什么?除 ...
- Java基础教程:Lambda表达式
Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...
- Java基础教程:泛型基础
Java基础教程:泛型基础 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚 ...
- Java基础教程:多线程基础(1)——基础操作
Java:多线程基础(1) 实现多线程的两种方式 1.继承Thread类 public class myThread extends Thread { /** * 继承Thread类,重写RUN方法. ...
随机推荐
- 进程相关的API函数
0x01. ID与句柄 如果我们成功创建一个进程之后,CreateProcess会返回四个数据,id和句柄 句柄的话就是 当前进程私有的句柄表索引(这是当前进程,给别进程也没用) 每个进程都有一张自己 ...
- 【总结】mybatis分页(实现 + 原理)
1.mybatis pageHelper分页实现 (1)引入依赖 (2)配置pageHelper插件 <configuration> <!-- 引入 pageHelper插件 --& ...
- SpringApplication.run(xxx.class, args)背后的东东——整体脉络
从spring到springmvc,再到springboot.springcloud,应用程序api开发调用方面都已经非常熟悉,但对spring背后的扩展机制:为何一个简单的main方法可以实现这么强 ...
- 教你如何使用github+jsDelivr搭建免费图床
前言 之前写了一篇文章,教你如何使用Typora+PicGo实现图片自动上传到图床 . 这里我用的是七牛图床,七牛图床有一定的免费使用量(没记错的话应该是10个G),如果你的存储量超过这个大小就需要付 ...
- 原生JS结合cookie实现商品评分组件
开发思路如下: 1.利用JS直接操作DOM的方式开发商品评分组件,主要实现功能有:显示评价评分的样式以及将用户操作后对应的数据返回到主页面 2.主页面引入商品评分组件的js文件并根据规定格式的数据,生 ...
- centos6-增加阿里yum源
1.获取阿里的yum源覆盖本地官方yum源 wget -O /etc/yum.repos.d/CentOS-ali.repo http://mirrors.aliyun.com/repo/Centos ...
- MySQL连接报错(错误:1130)
1. 原因 显示这个错误是因为没有连接到该机器MySQL数据库的权限,这是在一开始安装MySQL是默认设置的. 在数据库mysql下有一张名为`user`的表,其中的字段user下的root的值默认为 ...
- learning to Estimate 3D Hand Pose from Single RGB Images论文理解
持续更新...... 概括:以往很多论文借助深度信息将2D上升到3D,这篇论文则是想要用网络训练代替深度数据(设备成本比较高),提高他的泛性,诠释了只要合成数据集足够大和网络足够强,我就可以不用深度信 ...
- leetcode 43:construct-binary-tree-from-inorder
题目描述 给出一棵树的中序遍历和后序遍历,请构造这颗二叉树 注意: 保证给出的树中不存在重复的节点 Given inorder and postorder traversal of a tree, c ...
- 谈谈synchronized
为什么要用synchronized关键字: synchronized是java的一种内部锁,是一种排他锁,通常也被称为悲观锁,它能够保障原子性,可见性,有序性. 当多个线程去调用同一个方法的时候,如果 ...