java中的printnb_javaI/O系统笔记

1、File类

File类的名字有一定的误导性;我们可能认为它指代的是文件,实际上却并非如此。它既能代表一个

特定文件的名称,又能代表一个目录下的

一组文件的名称。

1.1、目录列表器

如果需要查看目录列表,可以通过file.list(FilenameFilter)方法来获取过滤后的文件目录列表(返回类型是String[])。

例子:https://github.com/xu509/Java-practise/blob/master/src/test/file/directory/DirList2.java

1.2 目录使用工具

产生文件集的工具类 :

https://github.com/xu509/Java-practise/blob/master/src/test/file/directory/Directory.java

处理文件类:

https://github.com/xu509/Java-practise/blob/master/src/test/file/directory/ProcessFiles.java

1.3 目录的检查以及创建 常用File类方法:f.isFile(), f.isDirectory(),f.mkdirs();

2、输入和输出

2.1、InputStream类型

InputStream的作用是用来表示那些从不同数据源产生输入的类。

数据源包括: 1、字节数组。2、String对象。3、文件。4、“管道”,即一端输入,另一端输出。5、一个由其他种类的流组成的序列。6、其他数据源,如Internet连接。

其中FilterInputStream为装饰器类提供基类。

2.2、OutputStream类型

该类别的类决定了输出所要去往的目标:字节数组、文件或管道。

FilterOutputStream为装饰器类提供基类。

3、添加属性和有用的接口

3.1、通过FilterInputStream从InputStream读取数据

FilterInputStream类能够完成两件完全不同的事情。其中,

DataInputStream:允许我们读取不同的基本类型数据以及String对象。

其他FilterInputStream类则在内部修改InputStream的行为方式:

BufferedInputStream :是否缓冲,可防治每次读取时都进行实际写操作。

LineNumberInputStream :跟踪输入流的行号,可调用getLineNumber()和setLineNumber(int)。

PushbackInputStream:具有“能弹出一个字节的缓冲区。”因此可以将督导的最后一个字符回退。

3.1、通过FilterInputStream从InputStream读取数据 以及是否把单一字符推回输入流等等。

3.2、通过FilterOutPutStream从OutputStream写入

DataOutputStream  : 可以按照可移植的方式向流中写入基本类型数据。

PrintStream: 用于格式化输出打印,具备方法print()和pringln().

BufferedOutputStream:它对数据流使用缓冲技术,可调用flush()清空缓冲区。

4、Reader和Writer

java1.1后加入的,设计Reader和Writer继承结构主要是为了国际化。老的I/O流继承层次结构仅支持8位字节流,并且不能很好地处理16位Unicode字符。有时我们必须把来自“字节”层次结构中的类和“字符”层次结构的类结合起来使用。为了实现这个目的,要用到“适配器”类:InputStreamReader可以把InputStream转换为Reader,而OutputStreamWriter可以把OutputStream转换为Writer。

4.1、数据的来源和去处

尽量尝试使用Reader和Writer,一旦程序代码无法成功编译,我们就会发现自己不得不使用面向字节的类库。

来源于去处:Java 1.0 类 相应的 Java 1.1 类InputStream  OutputStream  FileInputStream FileOutputStream StringBufferInputStream(已弃用) 。。Reader 适配器:InputStreamReader Writer 适配器:OutputStreamWriter  FileReader FileWriter StringReader StringWriter

4.2、更改流的行为

过滤器:Java 1.0类相应的Java 1.1类     FilterInputStream FilterReaderFilterOutputStreamFilterWriter(抽象类,没有子类)BufferedInputStream      BufferedReader(有readLine())BufferedOutputStreamBufferedWriterDataInputStream                                                DataInputStream,需要readline()时使用BufferedReaderPrintStreamPrintWriterLineNumberInputStream(已弃用)LineNumberReaderStreamTokenizerStreamTokenizer(使用接受Reader的构造器)PushbackInputStreamPushbackReader

4.3、未发生变化的类

DataOutputStream,File,RandomAccessFilemSequenceInputStream

5、自我独立的类:RandomAccessFile

RandomAccessFile适用于由大小已知的记录组成的文件,我们可以使用seek()将记录从一处转移到另一处,然后读取或者修改记录。

RandomAccessFile支持搜寻方法,并且只适用于文件。JDK1.4中,RandomAccessFile的大多数功能由nio存储映射文件所取代。

6、I/O流的典型使用方式

6.1、缓冲输入文件

使用BufferedReader的readLine来读取文件。

public static String

read(String filename) throws IOException {

// Reading input by lines:

BufferedReader in = new BufferedReader(

new FileReader(filename));

String s;

StringBuilder sb = new StringBuilder();

while ((s = in.readLine()) != null)

sb.append(s + "\n");

in.close();

return sb.toString();

}

FileReader来创建输入流,再通过BufferedReader来装饰。

例子:https://github.com/xu509/Java-practise/blob/master/src/test/file/excerise/BufferReaderExercise.java

6.2、从内存输入

使用BufferInputFile.read()读入的结果来创建StringReader。

public class MemoryInput {

public static void main(String[] args)

throws IOException {

StringReader in = new StringReader(

BufferedInputFile.read("MemoryInput.java"));

int c;

while ((c = in.read()) != -1)

System.out.print((char) c);

}

}

注意in.read()是以int形式返回下一字节,因此必须类型转换为char才能正确打印。

6.3、格式化的内存输入 要读取格式化的数据,可以使用DataInputStream,这是一个面向字节的I/O类(不是面向字符)。

例子:

try {

DataInputStream in = new DataInputStream(

new ByteArrayInputStream(

BufferedInputFile.read(

"file/example3.txt").getBytes()));

while (true)

System.out.print((char) in.readByte());

} catch (EOFException e) {

System.err.println("End of stream");

}

通过捕获异常来检测输入末尾,但这是对异常特性的错误使用

DataInputStream in = new DataInputStream(

new BufferedInputStream(

new FileInputStream("file/example3.txt")));

while (in.available() != 0)

System.out.print((char) in.readByte());

6.4、基本的文件输出 FileWriter对象可以向文件写入数据。通常会用BufferedWriter将其包装起来用以缓冲输出。

例:

static String file = "file/BasicFileOutput.out";

public static void main(String[] args)

throws IOException {

BufferedReader in = new BufferedReader(

new StringReader(

BufferedInputFile.read("src/io/BasicFileOutput.java")));

PrintWriter out = new PrintWriter(

new BufferedWriter(new FileWriter(file)));

int lineCount = 1;

String s;

while ((s = in.readLine()) != null)

out.println(lineCount++ + ": " + s);

out.close();

// Show the stored file:

System.out.println(BufferedInputFile.read(file));

}为了格式化输出,用PrintWriter装饰BufferedWriter。

文本输出的快捷方式

JAVA SE5在PrintWriter中添加了一个辅助构造器,使得不需要每次创建PrintWriter的时候都进行包装工作。

旧 :

PrintWriter out = new PrintWriter(

new BufferedWriter(new FileWriter(file)));

新:

PrintWriter out = new PrintWriter(file);新旧效果相同,其他常见的写入任务都没有快捷方式。

使用缓冲(BufferedReader,BufferedWriter)和不使用的区别:

前者将一部分内存作为缓冲区,使每次操作在内存中操作,而不是直接操作文件,等文件关闭或者缓冲区满后才往文件中写。

如果需要大量的读写,使用缓冲会提高性能。如果需要立即生效,则不需要用缓冲。

6.5、存储和恢复数据 我们可以用

DataOutputStream写入数据,并用

DataInputStream恢复数据。另这2个流都是面向字节的,需用使用InputStream以及OutputStream。

public class StoringAndRecoveringData {

public static void main(String[] args)

throws IOException {

DataOutputStream out = new DataOutputStream(

new BufferedOutputStream(

new FileOutputStream("file/Data.txt")));

out.writeDouble(3.14159);

out.writeUTF("That was pi");

out.writeDouble(1.41413);

out.writeUTF("Square root of 2");

out.close();

DataInputStream in = new DataInputStream(

new BufferedInputStream(

new FileInputStream("file/Data.txt")));

System.out.println(in.readDouble());

// Only readUTF() will recover the

// Java-UTF String properly:

System.out.println(in.readUTF());

System.out.println(in.readDouble());

System.out.println(in.readUTF());

}

}

根据API可以发现,DataOutputStream可以写入所有基于基本类型的数据。

6.6、读写随机访问文件 使用RandomAccessFile类似组合使用了DataInpuStream和DataOutputStream。

static String file = "rtest.dat";

static void display() throws IOException {

RandomAccessFile rf = new RandomAccessFile(file, "r");

for (int i = 1; i < 3; i++)

System.out.println(

"Value " + i + ": " + rf.readInt());

System.out.println(rf.readUTF());

rf.close();

}

public static void main(String[] args)

throws IOException {

RandomAccessFile rf = new RandomAccessFile(file, "rw");

for (int i = 1; i < 3; i++)

rf.writeInt(i);

rf.writeUTF("The end of the file");

rf.close();

display();

rf = new RandomAccessFile(file, "rw");

rf.seek(2 * 2);//使用seek在文件中移动 查找精度类型,int2字节,第二个即是2*2

rf.writeInt(9);//修改第二个

rf.close();

display();

构造参数第二个自行选择:r  - 只读,rw - 读写。

6.7、管道流

PipedInputStream、PipedOutputStream、PipedReader和PipedWriter的价值在于多线程,管道流用于任务之间的通信。

7、文件读写的实用工具 因为javaI/O中使用装饰者模式,使得类使用起来无比复杂,故需要设计添加帮助类完成基本任务。

https://github.com/xu509/Java-practise/blob/master/src/net/mindview/util/TextFile.java

该工具类实现读取文件为String类型,写入str等简单功能。

7.1、读取二进制文件

public class BinaryFile {

public static byte[] read(File bFile) throws IOException {

BufferedInputStream bf = new BufferedInputStream(

new FileInputStream(bFile));

try {

byte[] data = new byte[bf.available()];

bf.read(data);

return data;

} finally {

bf.close();

}

}

public static byte[]

read(String bFile) throws IOException {

return read(new File(bFile).getAbsoluteFile());

}

}

练习:使用上述工具类,统计文件中字符出现的次数/

统计字节出现的次数:

https://github.com/xu509/Java-practise/blob/master/src/test/file/excerise/RecordKeyMap.java

8、标准I/O 标准I/O既是Unix中的 “程序所使用单一信息流”的概念。程序中所有输入都可以来自

标准输入,所有输出也都可以发送到

标准输出,所有错误信息都可以发送到

标准错误。

标准I/O的意义在于:我们可以很容易地把程序串联起来,一个程序的标准输出可以成为另一个程序的标准输入。

8.1、从标准输入中读取

JAVA提供了 System.in、System.out和System.err 标准I/O模型。

System.out和System.err已经事先包装成了printStream对象。

System.in却是一个没有包装过的未经加工的InputStream。所以使用需要对其进行包装。

包装步骤:

BufferedReader stdin = new BufferedReader(

new InputStreamReader(System.in));其中InputStreamReader是适配器。

8.2、将System.out转换成PrintWriter

public class ChangeSystemOut {

public static void main(String[] args) {

PrintWriter out = new PrintWriter(System.out, true);

out.println("Hello, world");

}

} System.out 是一个 PrintStream,也是OutputStream,PrintWriter有一个可以接受OutputStream的构造器。

8.3、标准I/O重定向 java 的 System 类提供了 setIn(InputStream),setOut(PrintStream),setErr(PrintStream) 来对标准输入、输出和错误I/O流进行重定向。

例子:https://github.com/xu509/Java-practise/blob/master/src/io/Redirecting.java

例子中将标准输出和标准错误重定向到另一个文件,并且在最后恢复了标准输出。需注意的是,I/O重定向操纵的是字节流。

9、进程控制

提供一个工具类让java内部执行其他操作系统的程序。

工具类:https://github.com/xu509/Java-practise/blob/master/src/net/mindview/util/OSExecute.java

自定义异常:https://github.com/xu509/Java-practise/blob/master/src/net/mindview/util/OSExecuteException.java

执行类:https://github.com/xu509/Java-practise/blob/master/src/io/OSExecuteDemo.java

10、新I/O

JDK1.4后提供了新的I/O类库,其目的在于提高速度。

新I/O提出了通道和缓冲器的概念,我们可以把通道理解为一个包含煤层(数据)的矿藏,而缓冲器则是派送到矿藏的卡车。我们只和缓冲器交互,而通道也只和缓冲器交互。

ByteBuffer对象就是唯一与通道交互的缓冲器,可以存储未加工字节的缓冲器。ByteBuffer用于基础类型和字节形式的读取或输出,但无法输出或读取对象,包括字符串类型。

旧I/O类库中的FileInputStream,FileOutputStream以及RandomAccessFile都被修改,用以产生FileChannel(通道),这些都是字节操纵流,而Reader和Writer就不能用于产生通道;但是Channels类提供了实用方法,用于在通道中产生Reader和Writer。

上述三种流产生通道的例子:

private static final int BSIZE = 1024;

public static void main(String[] args) throws Exception {

// Write a file:

FileChannel fc =

new FileOutputStream("file/nio/data.txt").getChannel();

fc.write(ByteBuffer.wrap("Some text ".getBytes()));

fc.close();

// Add to the end of the file:

fc =

new RandomAccessFile("file/nio/data.txt", "rw").getChannel();

fc.position(fc.size()); // Move to the end

fc.write(ByteBuffer.wrap("Some more".getBytes()));

fc.close();

// Read the file:

fc = new FileInputStream("file/nio/data.txt").getChannel();

ByteBuffer buff = ByteBuffer.allocate(BSIZE);

fc.read(buff);

buff.flip();//告知buff做好被读取字节的准备

while (buff.hasRemaining())

System.out.print((char) buff.get());

}

注意如果打算使用FileChannel在通知ByteBuffer读取后执行进一步的read()操作,每当进行read()后都必须使用flip()方法告知缓冲器做好被读取的准备,我们就必须调用clear()来为下一次的read()做好准备,如下:

public class ChannelCopy {

private static final int BSIZE = 1024;

public static void main(String[] args) throws Exception {

args = new String[2];

args[0] = "file/example3.txt";

args[1] = "file/nio/copy.out";

if (args.length != 2) {

System.out.println("arguments: sourcefile destfile");

System.exit(1);

}

FileChannel

in = new FileInputStream(args[0]).getChannel(),

out = new FileOutputStream(args[1]).getChannel();

ByteBuffer buffer = ByteBuffer.allocate(BSIZE);

while (in.read(buffer) != -1) {

buffer.flip(); // Prepare for writing

out.write(buffer);

buffer.clear();  // Prepare for reading

}

}

}

创建2个通道,一个用于读,而另一个用于写,使用缓冲器进行读写,注意缓冲器flip(),clear()的使用。

上面程序并不是处理此类问题最理想的方式,特殊方法transferTo()和transferFrom()允许我们将一个通道和另一个通道直接相连。

关键代码:

in.transferTo(0, in.size(), out);

ByteBuffer b = ByteBuffer.allocate(BSIZE);

while (in.read(b,in.size()) != -1) {

b.flip();

in.write(b,in.size()+1);

b.clear();

}

注意通道read和write的改变,以及2个连接方法的用法。

10.1、转变数据

使用CharBuffer()进行转换字符,然后通过asCharBuffer()可输出缓冲器。

例子:https://github.com/xu509/Java-practise/blob/master/src/io/BufferToText.java

对于获取的字节,要么在写入文件的时候就转换成字符,要么就在缓冲器输出的时候进行编码转换为字符。可以使用Charset类来实现功能。

如:(1)

buff.rewind();//返回数据开始部分

String encoding = System.getProperty("file.encoding");

System.out.println("Decoded using " + encoding + ": "

+ Charset.forName(encoding).decode(buff));通过Charset.forName(encoding)获取Charset对象,然后对缓冲器进行解码。

(2)

fc = new FileOutputStream("data2.txt").getChannel();

fc.write(ByteBuffer.wrap(

"Some text".getBytes("UTF-16BE")));//输入时进行编码

fc.close();在写入时即使用编码。

(3)通过CharBuffer向ByteBuffer写入

buff = ByteBuffer.allocate(24); // More than needed

buff.asCharBuffer().put("Some text");//缓冲器输出时进行编码

fc.write(buff);

10.2、获取基本类型 ByteBuffer只保存字节类型,但可以从其所容纳的字节中产生不同的基本类型。

完整例子:

https://github.com/xu509/Java-practise/blob/master/src/io/GetData.java

获取char:

bb.asCharBuffer().put("Howdy!");

char c;

while ((c = bb.getChar()) != 0)

printnb(c + " ");

获取short:

bb.asShortBuffer().put((short) 471142);

print(bb.getShort());

bb.rewind();

其中asCharBuffer()和asShortBuffer()都获取了该缓冲器上的视图。

10.3、视图缓冲器(View buffer) 视图缓冲器可以让我们通过某个特定的基本数据类型的视窗查看其底层的ByteBuffer。ByteBuffer依然是实际存储数据的地方,“支持”着前面的视图,因此,对视图的任何修改都会映射称为对ByteBuffer中数据的修改(即视图的put方法)。

访问即修改底层ByteBuffer的例子:

public class IntBufferDemo {

private static final int BSIZE = 1024;

public static void main(String[] args) {

ByteBuffer bb = ByteBuffer.allocate(BSIZE);

IntBuffer ib = bb.asIntBuffer();

// Store an array of int:

ib.put(new int[]{11, 42, 47, 99, 143, 811, 1016});

// Absolute location read and write:

System.out.println(ib.get(3));

ib.put(3, 1811);

// Setting a new limit before rewinding the buffer.

ib.flip();

while (ib.hasRemaining()) {

int i = ib.get();

System.out.println(i);

}

}

}

ByteBuffer通过不同的视图显示方式也不同

例子 : https://github.com/xu509/Java-practise/blob/master/src/io/ViewBuffers.java

当数据为8字节数组 :

new byte[]{0, 0, 0, 0, 0, 0, 0, 'a'}不同的视图显示不同:

Byte Buffer 0 -> 0, 1 -> 0, 2 -> 0, 3 -> 0, 4 -> 0, 5 -> 0, 6 -> 0, 7 -> 97,

Float Buffer 0 -> 0.0, 1 -> 1.36E-43,

Int Buffer 0 -> 0, 1 -> 97,

Long Buffer 0 -> 97,

Short Buffer 0 -> 0, 1 -> 0, 2 -> 0, 3 -> 97,

Double Buffer 0 -> 4.8E-322,Char Buffer 0 -> ,1 -> , 2-> ,3 -> a

字节存放次序:不同的机器可能会使用不同的字节排序方法来存储数据。“big endian”(高位优先)将最重要的字节放在地址最低的存储单元。“little endian”(低位优先) 则是将最重要的字节放在地址最高的存储器单元。当存储量大于一个字节时,就要考虑字节的顺序问题。

ByteBuffer是以高位优先的形式存储数据的,并且数据在网上传送时也常常使用高位优先的形式。

我们可以使用带参数的ByteOrder.BIG_ENDIAN或ByteOrder.LITTLE_ENDIAN的order()方法改变排序方式。

bb.order(ByteOrder.BIG_ENDIAN);完整: https://github.com/xu509/Java-practise/blob/master/src/io/Endians.java

10.4、用缓冲器操纵数据当需要将字节数组写入文件中时,使用ByteBuffer.wrap()方法将字节数组包装,使用getChannel方法在FileOutputStream上打开一个通道,接着将缓冲器的数据写入通道中。

10.5、缓冲器的细节Buffer由数据与4个索引组成,这4个索引hi:mark(标记)、position(位置)、limit(界限)和 capacity(容量)。

flip() : 将limit设置为position,position设置为0。此方法用于准备从缓冲区读取已经写入的数据。

remaining(): 返回(limit - position)。

hasRemaining(): 若介于position和limit之间的元素,则返回true()

研究方法对索引影响的例子 : https://github.com/xu509/Java-practise/blob/master/src/io/UsingBuffers.java

10.6、内存映射文件内存映射文件允许我们创建和修改那些因为太大而不能放入内存的文件。有了内存映射文件,我们就可以假定整个文件都放在内存中,而且可以完全把它当做非常大的数组来访问。

public class LargeMappedFiles {

static int length = 0x8FFFFFF; // 128 MB

public static void main(String[] args) throws Exception {

MappedByteBuffer out =

new RandomAccessFile("file/example1.txt", "rw").getChannel()

.map(FileChannel.MapMode.READ_WRITE, 0, length);

for (int i = 0; i < length; i++)

out.put((byte) 'x');

print("Finished writing");

for (int i = length / 2; i < length / 2 + 20; i++)

printnb((char) out.get(i));

}

}如上图,为了能同时读写大文件,使用RandomAccessFile来获取通道,然后使用map()方法来产生MappedByteBuffer。

MappedByteBuffer是由ByteBuffer继承而来,因此它具有ByteBuffer的所有方法。

性能上使用映射文件访问要比旧的缓冲输入输出要高出不少。

测试类: https://github.com/xu509/Java-practise/blob/master/src/io/MappedIO.java

10.7、文件加锁

JDK1.4引入了文件加锁机制,允许我们同步访问某个作为共享资源的文件,通过通道的tryLock,或者lock方法,可以获得整个文件的锁,或部分的

FileLock fl = fos.getChannel().tryLock();

fl.release();

可通过添加参数来对文件的一部分上锁

tryLock(long position,long size,boolean shared) 或者 lock(...,...,...)

第三个参数决定了锁是独占锁还是共享锁,第一第二个参数决定了文件的加锁区域,而没有参数的加锁方法会对整个文件进行加锁。

独占锁或者共享锁的支持必须通过底层的操作系统提供,如果操作系统不支持共享锁,则会提供独占锁。可以通过FileLock.isShared()查询。

对映射文件的部分上锁

对大文件的不同部分加锁:

https://github.com/xu509/Java-practise/blob/master/src/io/LockingMappedFiles.java

11、压缩

Java I/O库提供读写压缩格式的数据流,使用它们进行封装以提供压缩功能,这些类不是从 Reader 和 Writer 派生出来,而是属于InputStream 和 OutputStream。

压缩类功能CheckedInputStream GetCheckSum() 为任何InputStream产生校验和(不仅是解压缩)CheckedOutputStreamGetCheckSum()为任何OutputStream产生校验和(不仅是压缩)DeflaterOutputStream压缩类的基类ZipOutputStream一个DeflaterOutputStream,用于将数据压缩成Zip文件格式GZIPOutputStream一个DeflaterOutputStreamm,用于将数据压缩成GZIP文件格式InflaterInputStream解压缩类的基类ZipInputStream一个InflaterInputStream,用于解压缩Zip文件格式的数据GZIPInputStream 一个InflaterInputStream,用于解压缩GZIP文件格式的数据

11.1 用GZIP进行简单压缩

如果对单个数据流(而不是互异数据)进行压缩,那么它可能是比较适合的选择

BufferedReader in2 = new BufferedReader(

new InputStreamReader(new GZIPInputStream(

new FileInputStream("test.gz"))));

BufferedOutputStream out = new BufferedOutputStream(

new GZIPOutputStream(

new FileOutputStream("test.gz")));

11.2 用Zip进行多文件压缩

支持Zip格式的Java库更加全面。利用该库可以方便的保存多个文件,甚至一个独立的类,使得读取Zip文件更加方便。

如下例,Checksum有2个类型,Adler32(更快)和CRC32(更准确)。

写入ZIP文件:

FileOutputStream f = new FileOutputStream("test.zip");

CheckedOutputStream csum =

new CheckedOutputStream(f, new Adler32());

ZipOutputStream zos = new ZipOutputStream(csum);

BufferedOutputStream out =

new BufferedOutputStream(zos);

zos.setComment("A test of Java Zipping");

// No corresponding getComment(), though.

for (String arg : args) {

print("Writing file " + arg);

BufferedReader in =

new BufferedReader(new FileReader(arg));

zos.putNextEntry(new ZipEntry(arg));

int c;

while ((c = in.read()) != -1)

out.write(c);

in.close();

out.flush();

}

out.close();对每一个要加入压缩档案的文件,都需要调用putNextEntry(),将其传递个一个ZipEntry对象。

读取ZIP文件:

FileInputStream fi = new FileInputStream("test.zip");

CheckedInputStream csumi =

new CheckedInputStream(fi, new Adler32());

ZipInputStream in2 = new ZipInputStream(csumi);

BufferedInputStream bis = new BufferedInputStream(in2);

ZipEntry ze;

while ((ze = in2.getNextEntry()) != null) {

print("Reading file " + ze);

int x;

while ((x = bis.read()) != -1)

System.out.write(x);

}

if (args.length == 1)

print("Checksum: " + csumi.getChecksum().getValue());

bis.close();

更简单的方法:

ZipFile zf = new ZipFile("test.zip");

Enumeration e = zf.entries();

while (e.hasMoreElements()) {

ZipEntry ze2 = (ZipEntry) e.nextElement();

print("File: " + ze2);

// ... and extract the data as before

}

完整例子:https://github.com/xu509/Java-practise/blob/master/src/io/ZipCompress.java

11.3 Java档案文件

jar [options] destination [manifest] inputfile(s)

options 是一个字母集合(不需要输入任何“-”或其他任何标示符),一下字符在Unix和Linux系统的tar文件中也具有相同的意义.

c                创建一个新的或空的压缩文档t列出目录表x解压所有文件x file解压该文件f                             意指:“我打算指定一个文件名。” 如果没有用这个选项, jar假设所有的输入都来自于标准输入。m表示第一个参数将是用户自建的清单文件的名字v 产生详细输出,描述jar所做的工作O只存储文件,不压缩文件(用来创建一个可放在类路径中的JAR文件)M不自动创建文件清单

典型用法:

jar cf myJarFile.jar *.class  -

创建一个名为myJarFile.jar的JAR文件,该文件包含了当前目录中的所有类文件,以及自动产生清单文件

jar cmf myJarFile.jar myManifestFile.mf *.class - 其他与上例相同,添加一个名为myManifestFile.mf的用户自建清单文件

jar tf myJarFile.jar  - 产生myJarFile.jar内所有文件的一个目录表

jar tvf myJarFile.jar  - 提供有关myJarFile.jar中的文件的更详细的信息

假定audio、classes和image是子目录,下面的命令将所有子目录合并到文件myApp.jar中,其中也包括了 "v"标志,当jar程序运行时,该标志可以提供更详细的信息 -   jar cvf myApp.jar audio classes image

12、对象序列化

Java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。

利用对象的序列化可以实现轻量级持久性。

要序列化一个对象,首先需要创建一个OutputStream对象,然后使用ObjectOuptStream进行装饰。然后,只需要调用writeObject()即可将对象序列化,并将其发送给OutputStream。要反响进行该过程,需要将一个InputStream封装在ObjectInputStream内,然后调动readObject(),获得一个Object引用,然后对其向下转型则能直接设置他们。

输出序列化对象:

OutputStream outstream = new FileOutputStream(filepath);

ObjectOutputStream out = new ObjectOutputStream(outstream);

//        out.writeObject("test write");

out.writeObject(a1);

out.close();

输入序列化对象:

ObjectInputStream in = new ObjectInputStream(new FileInputStream(filepath));

String s = (String) in.readObject();

Object obj = in.readObject();

in.close();

详细例子 : https://github.com/xu509/Java-practise/blob/master/src/io/Worm.java

12.1 寻找类

获取序列化后的文件,重新进行包装时需要原类的.class文件,否则无法包装。

12.2 序列化的控制 如果需要考虑特殊的安全问题,希望对象的一部分被序列化,或者一个对象被还原后,其子对象需要重新创建。

在这些特殊情况下,可通过实现Externalizable接口代替Serializable接口,来对序列化过程进行控制。这个接口增添两个方法:writeExternal()、readExternal()。这两个方法会在序列化与反序列化还原的过程中被自动调用。

https://github.com/xu509/Java-practise/blob/master/src/io/Blips.java

如上例,Blip2因为构造方法非public所以无法反序列化还原。这是Externalizable和Serializable的不同,Serizalizable接口不依赖构造方法还原,而Externalizable还原时会调用所有的默认构造方法,然后再调用readExternal()。

https://github.com/xu509/Java-practise/blob/master/src/io/Blip3.java

Externalizable在反序列化时,需要向对象内所有的成员对象写入数据,否则还原后的对象中的成员对象数据为空。

public void writeExternal(ObjectOutput out)

throws IOException {

out.writeObject(s);

out.writeInt(i);

}

public void readExternal(ObjectInput in)

throws IOException, ClassNotFoundException {

s = (String) in.readObject();

i = in.readInt();

}

transient(瞬时)关键词

除了Externalizeable外,可以用transient在Serializable对象中逐个字段关闭序列化。

例子: https://github.com/xu509/Java-practise/blob/master/src/io/Logon.java

private transient String password;

private Date date = new Date();

当对象被恢复时,password域会变成"null",date对象不会发生变化,序列化的时候是多少还原时就是多少。

Externalizable的替代方法

如果不希望实现Externalizable方法,我们可以实现Serializable接口,并且

添加名为writeObject()和readObject()方法。这样一旦对象被序列化或者反序列化还原,就会自动地分别调用这两个方法,这些方法必须有准确的方法特征签名:

private void writeObject(ObjectOutputStream stream)

throws IOException ;

private void readObject(ObjectInputStream stream)

throws IOException, ClassNotFoundException;

https://github.com/xu509/Java-practise/blob/master/src/io/SerialCtl.java

private void writeObject(ObjectOutputStream stream)

throws IOException {

stream.defaultWriteObject();

stream.writeObject(b);

}

private void readObject(ObjectInputStream stream)

throws IOException, ClassNotFoundException {

stream.defaultReadObject();

b = (String) stream.readObject();

}版本控制

由于Java版本控制机制国语简单,因而对于序列化的支持,只适用于短期存储或应用之间的RMI。

12.3 使用”持久性“

我们将2个对象(他们都具有指向第三个对象的引用 )进行序列化,当我们恢复他们时,第三个对象会只出现一次吗?如果两个对象序列化成独立的文件,然后在代码的不同部分对它们进行反序列化还原,又会怎么样呢?

https://github.com/xu509/Java-practise/blob/master/src/io/MyWorld.java

经过上述程序的试验,在同一个流内,2个对象引用了相同的地址。

https://github.com/xu509/Java-practise/blob/master/src/io/StoreCADState.java

在上面这个例子里,xPos,yPos,dimension都成功的序列化与反序列化了,但是static的color并没有成功的恢复。而Line类中的

/*序列化时记录static变量的值*/

public static void

serializeStaticState(ObjectOutputStream os)

throws IOException {

os.writeInt(color);

}

/*序列化时记录static变量的值*/

public static void

deserializeStaticState(ObjectInputStream os)

throws IOException {

color = os.readInt();

}方法则的作用就是将静态变量的序列化和反序列化。

13、XML

书中使用XOM类库来完成对XML的操作。

14、Preferences

Preferences API 与对象序列化相比,与对象持久性更密切,因为它可以自动存储和读取信息。不过它只能用于小的、受限的数据集合——我们只能存储基本类型和字符串,并且每个字符串的存储长度不能超过8K。

顾名思义,Preferences API用于存储和读取用户的偏好,以及程序配置项的设置。

Preferences是一个键值集合(类似映射),存储在一个节点层次结构中。简单例子:

public class PreferencesDemo {

public static void main(String[] args) throws Exception {

Preferences prefs = Preferences

.userNodeForPackage(PreferencesDemo.class);

prefs.put("Location", "Oz");

prefs.put("Footwear", "Ruby Slippers");

prefs.putInt("Companions", 4);

prefs.putBoolean("Are there witches?", true);

int usageCount = prefs.getInt("UsageCount", 0);

usageCount++;

prefs.putInt("UsageCount", usageCount);

for (String key : prefs.keys())

print(key + ": " + prefs.get(key, null));

// You must always provide a default value:

print("How many companions does Dorothy have? " +

prefs.getInt("Companions", 0));

}

}

/* Output: (Sample)

Location: Oz

Footwear: Ruby Slippers

Companions: 4

Are there witches?: true

UsageCount: 53

How many companions does Dorothy have? 4

*///:~

每次PreferencesDemo运行后,usageCount都会+1。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

outlook反应慢的原因_保险管怎么区分慢熔和快熔?

保险丝快熔与慢熔的区别所有双帽;对于这样的产品特性和安全性熔丝; gG的”&#xff0c;即&#xff0c;与接触帽组合接触;即&#xff0c;所述双(内/外盖)的盖。和一般的小型或地下加工厂&#xff0c;以便执行切割角&#xff0c;降低生产成本&#xff0c;这将选择单个帽铆接“单&…

java成员内部类_Java中的内部类(二)成员内部类

Java中的成员内部类(实例内部类)&#xff1a;相当于类中的一个成员变量&#xff0c;下面通过一个例子来观察成员内部类的特点public classOuter {//定义一个实例变量和一个静态变量private inta;private static intb;//定义一个静态方法和一个非静态方法public static voidsay(…

word 通配符_学会Word通配符,可以帮助我们批量处理好多事情

长文档需要批量修改或删除某些内容的时候&#xff0c;我们可以利用Word中的通配符来搞定这一切&#xff0c;当然&#xff0c;前提是你必须会使用它。通配符的功能非常强大&#xff0c;能够随意组合替换或删除我们定义的规则内容&#xff0c;下面易老师就分享一些关于查找替换通…

java存储键值结构_java-键值存储为主数据库

我将要开始一个项目,该项目的读写操作非常频繁且频繁.因此,环顾四周,我发现内存数据库正是为此目的而创建的.经过更多调查后,我进入了redis.Redis看起来很酷(虽然刚开始阅读,但是对此有很多了解).但是我主要只看过关系数据库,并且以元组和关系的方式来考虑数据(我认为我可以随着…

python 输入文件名查找_python 查找文件名包含指定字符串的方法

编写一个程序&#xff0c;能在当前目录以及当前目录的所有子目录下查找文件名包含指定字符串的文件&#xff0c;并打印出绝对路径。import osclass searchfile(object):def __init__(self,path.):self._pathpathself.abspathos.path.abspath(self._path) # 默认当前目录def fin…

java 运行 出现选择_Eclipse 运行出现java.lang.NoClassDefFoundError的解决方法

上篇博文也提到了这个问题&#xff0c;但没有深入的讲解。这次特意做了整理&#xff0c;详细解释其原因。先看错误java.lang.NoClassDefFoundError&#xff0c;显然是java虚拟机找不到指定的类&#xff0c;多数情况下是外部jar中的类。Eclipse的自动化&#xff0c;集成化&#…

设置熄屏_刚买的手机微信收不到信息提醒耽误事情,手机到手一定要这样设置...

手机使用过程中经常会遇到第三方软件接收不到信息提醒的状况&#xff0c;常常因此耽误了很多重要的事情&#xff0c;造成损失。特别是刚换新手机或者手机刚升级系统时发生的最多。一般都觉得是手机问题&#xff0c;其实只是手机的系统设置出现了问题&#xff0c;只要跟我按照以…

java判断对称素数_SM2非对称算法的原理及实现 Java SM2的代码案例 | 一生孤注掷温柔 | 小奋斗...

SM2椭圆曲线公钥密码算法&#xff1a;我国自主知识产权的商用密码算法&#xff0c;是ECC(Elliptic Curve Cryptosystem)算法的一种&#xff0c;基于椭圆曲线离散对数问题&#xff0c;计算复杂度是指数级&#xff0c;求解难度较大&#xff0c;同等安全程度要求下&#xff0c;椭圆…

multipartfile 获取音频时长_抖音音频下载捷径:一键提取音频,安卓+ios全通用,完全免费...

本文相关&#xff1a;抖音音频提取、抖音音频快捷指令、捷径怎么获取抖音音乐…昨天有抖友分享了一个抖音短视频链接&#xff0c;告诉我&#xff0c;她很喜欢这个视频里的歌曲&#xff0c;但是在很多歌曲app上面却找不到相同的版本&#xff0c;然后就问我&#xff0c;有没有什么…

python可以做特效吗_学习mel语言,Python,JavaScript到什么程度才能做一下大型特效,要自已开发插件脚本呢?...

感谢邀请。首先自己要在某一方面要擅长&#xff0c;认准一个定位。比如android是钥匙做前端应用软件的&#xff0c;python可以做爬虫及其人工智能&#xff0c;js做全段网页&#xff0c;java主要是做后端的1、我们程序员对于开发软件来说&#xff0c;无论你选择的是那种语言&…

POJ2513-Colored Sticks

/*思路&#xff1a;类似图论中“一笔画”问题&#xff0c;两根木棒的相连接的端点是一样的颜色&#xff0c;&#xff08;a,b&#xff09;--(b,c)--(c, d)....方法&#xff1a;trie树并查集&#xff0c; 利用trie树建立字符串和某一个节点的映射&#xff0c;并将这些和字符串构成…

php windows共享内存,给PHP开启shmop扩展实现共享内存

这篇文章主要介绍了关于给PHP开启shmop扩展实现共享内存&#xff0c;有着一定的参考价值&#xff0c;现在分享给大家&#xff0c;有需要的朋友可以参考一下在项目开发中&#xff0c;想要实现PHP多个进程之间共享数据的功能&#xff0c;让客户端连接能够共享一个状态&#xff0c…

导入ansys的实体怎么进行parameter_ANSYS在线缆线束设计中的仿真应用

ANSYS采用ANSYS Maxwell、Q3D、Twin Builder等电磁仿真软件&#xff0c;从线缆线束设计、寄生参数RLCG提取、到系统电磁兼容提供了全面仿真分析。创建模型ANSYS在Maxwell软件基础上提出针对用户定制化的“线缆线束设计工具包”&#xff0c;帮助客户参数化建立特定几何模型&…

怎么做95置信区间图_这种动态的OD图怎么做?简单3步快速搞定

之前在视频号中发过一个单车的出行数据可视化效果。动态展示了某天单车不同时段的运行情况&#xff0c;这种动态的OD可视化效果是如何制作的呢&#xff1f;使用的是kepler.gl进行制作的&#xff0c;其实非常简单&#xff0c;3步即可快速搞定。一、数据软件准备1、软件制作这种动…

php抖音跳转地址,PHP如何实现解析抖音无水印视频

问题来源很多时候你在douyin里看到了一个短视频&#xff0c;想复制下来自己编辑文字来发布&#xff0c;可是视频里的水印却是原者的。这个时候你想把水印去掉&#xff0c;你要如何做呢&#xff1f;这里提供PHP实现去除水印的主要方法&#xff0c;其实很简单。使用方法&#xff…

php 分割二维数组,拆分二维数组 php

把以下数组拆分&#xff1a;{"errcode": 0,"msg": "成功","data": {"list": [{"ticket_no": "1","options": ["周四301","周四302","周四303"],"play_ty…

Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解

1 /*2 Dijkstra算法用优先队列来实现&#xff0c;实现了每一条边最多遍历一次。 要知道&#xff0c;我们从队列头部找到的都是到3 已经"建好树"的最短距离以及该节点编号, 并由该节点去更新 树根 到其他点&#xff08;被更新的节点可以在队列中4 &#xff0c;也可以是…

php times33,PHP Hash算法:Times33算法代码实例

最近看书&#xff0c;里面提到了一些Hash算法。比较有印象的是Times33&#xff0c;当时理解不是很透测&#xff0c;今天写了段程序来验证了一下。先上代码&#xff1a;复制代码 代码如下:/*** CRC32 Hash function* param $str* return int*/function hash32($str){return crc3…

捡到vivo手机怎么清除账号_为什么现在买手机,很少会去考虑OPPO和vivo呢?看一下老板怎么说...

不知道大家是否注意到&#xff0c;近年来OPPO和vivo的报道越来越少&#xff0c;而华为、荣耀和小米出现的频率越来越高。此外&#xff0c;网络上还有另外一个声音&#xff0c;一个专业的机友朋友说&#xff0c;宁可选择小米、OPPO和vivo&#xff0c;为什么熟悉自己手机的人不考…

php分析图片中水印的位置,关于ThinkPHP打水印及设置水印位置的分析

这篇文章主要介绍了ThinkPHP打水印及设置水印位置的方法,结合实例形式分析了thinkPHP打印与设置水印的相关操作步骤与具体实现技巧,需要的朋友可以参考下本文实例讲述了ThinkPHP打水印及设置水印位置的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;最近在用Thin…