黑马程序员:Java基础总结
字节流&InputStream &OutputStream
字节流
字节流两个基类:
InputStream , OutputStream
类 OutputStream方法
输出流接受输出字节并将这些字节发送到某个接收器。
void |
write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。 |
void |
write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 |
abstract void |
write(int b) 将指定的字节写入此输出流。 |
类 FileOutputStream
FileOutputStream(String name, boolean append) 创建一个向具有指定 name 的文件中写入数据的输出文件流。 |
复制一个图片
FileOutputStream fos =
null
;
FileInputStream fis =
null
;
try
{
fos =
new
FileOutputStream(
"c:\\2.bmp"
);
fis =
new
FileInputStream(
"c:\\1.bmp"
);
byte
[] buf =
new
byte
[1024];
int
len = 0;
while
((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
类 BufferedOutputStream
BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 |
通过字节流的缓冲区完成复制mp3
BufferedInputStream bufis =
new
BufferedInputStream(
new
FileInputStream(
"c:\\0.mp3"
));
BufferedOutputStream bufos =
new
BufferedOutputStream(
new
FileOutputStream(
"c:\\1.mp3"
));
int
by = 0;
while
((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
类 ObjectOutputStream
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
public
static
void
writeObj()
throws
IOException
{
ObjectOutputStream oos =
new
ObjectOutputStream(
new
FileOutputStream(
"obj.txt"
));
oos.writeObject(
new
Person(
"lisi0"
,399,
"kr"
));
oos.close();
}
类 PipedOutputStream
可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream
对象,并由其他线程从连接的 PipedInputStream
读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于 毁坏 状态。
PipedOutputStream() 创建尚未连接到管道输入流的管道输出流。 |
PipedOutputStream(PipedInputStream snk) 创建连接到指定管道输入流的管道输出流。 |
必须使用多线程:
PipedInputStream in =
new
PipedInputStream();
PipedOutputStream out =
new
PipedOutputStream();
in.connect(out);
Read r =
new
Read(in);
Write w =
new
Write(out);
new
Thread(r).start();
new
Thread(w).start();
类 DataOutputStream
可以用于操作基本数据类型的数据的流对象
void |
writeInt(int v) 将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。 |
public
static
void
readData()
throws
IOException
{
DataInputStream dis =
new
DataInputStream(
new
FileInputStream(
"data.txt"
));
int
num = dis.readInt();
boolean
b = dis.readBoolean();
double
d = dis.readDouble();
System.
out
.println(
"num="
+num);
System.
out
.println(
"b="
+b);
System.
out
.println(
"d="
+d);
dis.close();
}
public
static
void
writeData()
throws
IOException
{
DataOutputStream dos =
new
DataOutputStream(
new
FileOutputStream(
"data.txt"
));
dos.writeInt(234);
dos.writeBoolean(
true
);
dos.writeDouble(9887.543);
dos.close();
ObjectOutputStream oos =
null
;
oos.writeObject(
new
O());
}
类 ByteArrayOutputStream
用于操作字节数组的流对象
ByteArrayInputStream :在构造的时候,需要接收数据源,。而且数据源是一个字节数组。
ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。
所以,不用进行close关闭
ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。
所以,不用进行close关闭
源设备,
键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘FileStream,内存 ArrayStream
键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘FileStream,内存 ArrayStream
byte[] |
toByteArray() 创建一个新分配的 byte 数组。 |
String |
toString() 使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。 |
//数据源。
ByteArrayInputStream
bis
=
new
ByteArrayInputStream(
"ABCDEFD"
.getBytes());
//数据目的
ByteArrayOutputStream
bos
=
new
ByteArrayOutputStream();
int
by = 0;
while
((by=bis.read())!=-1)
{
bos
.write(
by
);
}
System.out.println(bos.size());
System.out.println(bos.toString());
// bos.writeTo(new FileOutputStream("a.txt"))
类 InputStream方法
int |
available() 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。 (!多线程时读取或跳过的字节数可能小于该数,试图使用此方法的返回值分配缓冲区来实现读取和跳过是不正确的)
|
FileInputStream fis = new FileInputStream("fos.txt" );
// int num = fis.available();
byte[] buf = new byte[fis.available()]; //定义一个刚刚好的缓冲区。不用在循环了。
fis.read(buf);
System. out.println(new String(buf));
fis.close();
类 FileInputStream
和InputStream相似
类 BufferedInputStream
字段摘要 | |
---|---|
protected byte[] |
buf 存储数据的内部缓冲区数组。 |
protected int |
count 比缓冲区中最后一个有效字节的索引大 1 的索引。 buf[0] 到 buf[count-1] 的元素包含从底层输入流中获取的缓冲输入数据
|
protected int |
marklimit 调用 mark 方法后,在后续调用 reset 方法失败之前所允许的最大提前读取量。 |
protected int |
markpos 最后一次调用 mark 方法时 pos 字段的值。 |
protected int |
pos 缓冲区中的当前位置。 |
以下是JDK读取文件的过程
private
void
fill()
throws
IOException {
byte
[] buffer = getBufIfOpen();
if
(markpos < 0)
pos = 0;
/* no mark: throw away the buffer */
else
if
(pos >= buffer.length)
/* no room left in buffer */
if
(markpos > 0) {
/* can throw away early part of the buffer */
int
sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
}
else
if
(buffer.length >= marklimit) {
markpos = -1;
/* buffer got too big, invalidate mark */
pos = 0;
/* drop buffer contents */
}
else
{
/* grow buffer */
int
nsz = pos * 2;
if
(nsz > marklimit)
nsz = marklimit;
byte
nbuf[] =
new
byte
[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
if
(!bufUpdater.compareAndSet(
this
, buffer, nbuf)) {
// Can't replace buf if there was an async close.
// Note: This would need to be changed if fill()
// is ever made accessible to multiple threads.
// But for now, the only way CAS can fail is via close.
// assert buf == null;
throw
new
IOException(
"Stream closed"
);
}
buffer = nbuf;
}
count = pos;
int
n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if
(n > 0)
count = n + pos;
}
public
synchronized
int
read()
throws
IOException {
if
(pos >= count) {
fill();
if
(pos >= count)
return
-1;
}
return
getBufIfOpen()[pos++] & 0xff;
}
结论:
字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.
那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
所以,为了避免这种情况将读到的字节进行int类型的提升。
并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。
而在写入数据时,只写该int类型数据的最低8位。
字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.
那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
所以,为了避免这种情况将读到的字节进行int类型的提升。
并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。
而在写入数据时,只写该int类型数据的最低8位。
类 ObjectInputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。
类 PipedInputStream
管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从
PipedInputStream
对象读取,并由其他线程将其写入到相应的
PipedOutputStream
。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道
已损坏。
PipedInputStream(PipedOutputStream src) 创建 PipedInputStream ,使其连接到管道输出流 src 。 |
类 DataInputStream
int |
readInt() 参见 DataInput 的 readInt 方法的常规协定。可见有两个大接口DataInput,和DataOutput
|
类 ByteArrayOutputStream
参见ByteArraysInputStream相似