您现在的位置是:主页 > news > 网站维护怎么做/seo网络营销推广

网站维护怎么做/seo网络营销推广

admin2025/5/12 14:58:20news

简介网站维护怎么做,seo网络营销推广,网站需求文档,品牌建设年度工作总结文件高级技术一、常见文件类型处理一)属性文件属性文件很简单,一行表示一个属性,属性就是键值对,键和值用()或者(:)分隔。#ready to worknametangage 22phone 110Java使用专门的类java.util.Properties处理这种文件。主要方法&…

网站维护怎么做,seo网络营销推广,网站需求文档,品牌建设年度工作总结文件高级技术一、常见文件类型处理一)属性文件属性文件很简单,一行表示一个属性,属性就是键值对,键和值用()或者(:)分隔。#ready to worknametangage 22phone 110Java使用专门的类java.util.Properties处理这种文件。主要方法&…

文件高级技术

一、常见文件类型处理

一)属性文件

属性文件很简单,一行表示一个属性,属性就是键值对,键和值用(=)或者(:)分隔。

#ready to work

name=tang

age= 22phone= 110

Java使用专门的类java.util.Properties处理这种文件。主要方法:

public synchronized voidload(InputStream inStream)publicString getProperty(String key)public String getProperty(String key, String defaultValue)

Properties props = newProperties();try{

props.load(new FileReader("tang.properties"));

System.out.println("The name is " + props.getProperty("name"));

}catch(IOException e) {

e.printStackTrace();

}

优势:可以自动处理空格,自动忽略空行,以#或者!开头的会被视为注释。

二)压缩文件

Java SDK支持两种:gzip和zip,gzip只能压缩一个文件,而zip文件可以包含多个。

先看gzip:

java.util.zip.GZIPOutputStream

java.util.zip.GZIPInputStream

它们都是InputStream和OutputStream的子类,都是装饰类,GZIPOutputStream加到

已有的流上,就可以实现压缩,而GZIPInputStream加到已有的流上就可以实现解压。

public static voidgzip(String fileName) {

InputStream in= null;

String gzipFileName= fileName + ".gz";

OutputStream out= null;try{

in= newFileInputStream(fileName);

out= new GZIPOutputStream(newFileOutputStream(gzipFileName));

copy(in, out);

}catch(Exception e) {

e.printStackTrace();

}

}public static voidunGzip(String gzipFileName, String fileName) {

InputStream in= null;

OutputStream out= null;try{

in= new GZIPInputStream(newBufferedInputStream(newFileInputStream(gzipFileName)

));

out= newBufferedOutputStream(newFileOutputStream(fileName)

);

copy(in, out);

}catch(Exception e) {

e.printStackTrace();

}

}public static void copy(InputStream in, OutputStream out) throwsIOException {try{byte[] buf = new byte[1024];int count = 0;while ((count = in.read(buf)) != -1) {

out.write(buf,0, count);

}

}catch(Exception e) {

e.printStackTrace();

}finally{if (in != null) in.close();if (out != null) out.close();

}

}

zip支持压缩文件包中包含多个文件,Java API中的主要类是:

java.util.zip.ZipOutputStream

java.util.zip.ZipInputStream

ZipOutputStream可以写入多个文件,它有一个重要方法:

//在写入一个文件前,必须先调用该方法,表示准备写入一个压缩条目ZipEntry

public void putNextEntry(ZipEntry e) throws IOException

//每个压缩条目都有一个名称,这个名称是压缩文件的相对路径,如果以'/'结尾表示目录

public ZipEntry(String name)

/*** 压缩一个文件或者目录

*@paraminFile 表示输入,可以是文件或者目录

*@paramzipFile 表示输出的zip文件

**/

public static void zip(File inFile, File zipFile) throwsIOException {

ZipOutputStream zipOut= new ZipOutputStream(newBufferedOutputStream(newFileOutputStream(zipFile)));try{//输入文件不存在抛出异常

if (!inFile.exists())throw newFileNotFoundException(inFile.getAbsolutePath());

inFile=inFile.getCanonicalFile();

String rootPath=inFile.getParent();//如果根路径不是以"/"结尾

if (!rootPath.endsWith(File.separator)) {

rootPath+=File.separator;

}

addFileToZipOut(inFile, zipOut, rootPath);

}catch(Exception e) {

e.printStackTrace();

}finally{

zipOut.close();

}

}

public static void addFileToZipOut(File inFile, ZipOutputStream out, String rootPath) throwsIOException {

String relativePath=inFile.getCanonicalPath()

.substring(rootPath.length());if(inFile.isFile()) {

out.putNextEntry(newZipEntry(relativePath));

InputStream in= newBufferedInputStream(newFileInputStream(inFile)

);try{

copy(in, out);

}finally{

in.close();

}//如果是目录

} else{

out.putNextEntry(new ZipEntry(relativePath +File.separator));for(File f : inFile.listFiles()) {

addFileToZipOut(f, out, rootPath);

}

二、随机读写文件(RandomAccessFile)

一)用法

RandomAccessFile构造方法:

publicRandomAccessFile(String name, String mode)throwsFileNotFoundExceptionpublicRandomAccessFile(File file, String mode)throws FileNotFoundException

其中name和file,表示文件路径和File对象。mode表示打开模式:

1)r:只读

2)rw:读和写

3)rws:读和写,另外,要求文件内容和元数据的任何更新都同步到设备上。

4)rwd:读和写,另外,文件内容的更新同步到设备上,元数据更新不同步。

该类有类似于InputStream/OutputStream类似的读写字节流的方法。

另外,它还实现了DataInput/DataOutput接口。

public int read() throwsIOExceptionpublic int read(byte b[]) throwsIOExceptionpublic final int readInt() throwsIOExceptionpublic final void writeInt(int v) throwsIOExceptionpublic void write(byte b[]) throws IOException

另外还有两个read方法:

public final void readFully(byte b[]) throwsIOExceptionpublic final void readFully(byte b[], int off, int len) throws IOException

与对应的read方法的区别是,它们可以确保读够期望的长度,如果到了文件结尾也没读够,抛异常。

RandomAccessFile内部有一个文件指针,指向当前的读写位置,各种read/write操作都会自动更新

该指针。与流操作不同的是,RandomAccessFile可以获取该指针,也可以更改该指针。

//获取当前指针

public native long getFilePointer() throwsIOException//更改当前指针到pos

public native void seek(long pos) throws IOException

跳过输入流中的n个字节:

public int skipBytes(int n) throws IOException //通过更改指针实现

获取文件字节数:

public native long length() throws IOException

修改文件长度:

//如果当前文件的长度小于newLength,则文件会扩展,大于会收缩,文件指针比newLength//大则会调整到newLength

public native void setLength(long newLength) throws IOException

请避免使用以下两个方法:

public final void writeBytes(String s) throwsIOExceptionpublic final String readLine() throws IOException

三、内存映射文件

内存映射文件不是Java引入的概念,而是操作系统提供的一种功能,大部分操作系统都支持。

一)基本概念

所谓内存映射文件,就是将文件映射到内存,文件对应于内存的一个字节数组,对文件的操作

变为对这个字节数组的操作,而字节数组的操作直接映射到文件上。这种映射可以是文件的全部

区域也可以是部分区域。

内存映射文件特点:

1)使用的是操作系统内核内存空间,只有一次复制,比普通读写效率高

2)可被多个不同程序共享,一个程序对内存的修改,其他程序也可以看

到,这使得它特别适合不同程序间的通信

操作系统自身在加载可执行文件的时候,一般都利用了内存映射。

内存映射局限性:

因为是按页分配内存,对小文件来说浪费内存

二)用法

内存映射文件需要通过FileInputStream/FileOutputStream/RandomAccessFile,它们都有方法:

public FileChannel getChannel()

FileChannel都有方法:

/*** 该方法将当前文件映射到内存,映射结果就是MappedByteBuffer对象,它代表内存中的字节数组

* 如果映射区域超过了文件的范围,文件会自动扩展

*@parammode 表示映射模式:

* READ_ONLY:只读

* READ_WRITE:读写

* PRIVATE:私有模式,更改不反映到文件,也不被其他程序看到

*@paramposition 表示映射的起始位置

*@paramsize 表示映射的长度

*@return映射完成后,文件就可以关闭,对文件的后续读写可以通过MappedByteBuffer

**/

public MappedByteBuffer map(MapMode mode, longposition,long size) throwsIOException{

}

MappedByteBuffer是ByteBuffer的子类,ByteBuffer可以理解为封装了一个长度不可变的字节数组,

在内存映射文件中这个长度由map方法中的size决定。ByteBuffer有一个基本属性position,表示当前

读写位置,相关方法是:

public final int position() //获取当前读写位置

public final Buffer position(int newPosition) //修改当前读写位置

ByteBuffer中有很多基于当前读写位置的读写数据方法:

public abstract byte get() //从当前位置获取一个字节

public ByteBuffer get(byte[] dst) //从当前位置获取dst.length长度的字节到dst

public abstract int getInt() //从当前位置读取一个int

public final ByteBuffer put(byte[] src) //将字节数组src写入到当前位置

public abstract ByteBuffer putLong(long value) //将value写入到当前位置

这些方法读写后都会自动增加position,与之对应的还有一组方法可以指定position:

public abstract int getInt(int index) //从index处读取一个int

public abstract double getDouble(intindex)public abstract ByteBuffer putDouble(int index, doublevalue)public abstract ByteBuffer putLong(int index, long value)

这些方法在读写时,不会改变当前的读写位置。

MappedByteBuffer自己还定义了一些方法:

//检查文件内容是否真正加载到了内存,仅供参考

public final booleanisLoaded()//尽量将文件内容加载到内存

public finalMappedByteBuffer load()//将对内存的修改强制同步到硬盘上

public final MappedByteBuffer force()

四、标准序列化机制

序列化就是将对象转换为字节流,反序列化就是将字节流转换为对象。

一)基本用法

要让一个类支持序列化,只需要让这个类实现接口java.io.Serializable,该接口是一个标记接口。

读取/保存声明了Serializable接口的类可以使用ObjecOutputStream/ObjectInputStream流了。

ObjectOutputStream是OutputStream的子类,但实现了ObjectOutput接口,该接口是DataOutput

的子接口,增加了一个方法:

public void writeObject(Object obj) throws IOExceptio

该方法能把对象obj转化为字节,写到流中。

ObjectInputStream核心方法:

public Object readObject() throws ClassNotFoundException, IOException

该方法中流中读取字节,转化为对象。

public static void writeStudents(Liststudents)throwsIOException {

ObjectOutputStream out= newObjectOutputStream(new BufferedOutputStream(new FileOutputStream("students.dat")));try{

out.writeInt(students.size());for(Student s : students) {

out.writeObject(s);

}

}finally{

out.close();

}

}

public static List readStudents() throwsIOException,

ClassNotFoundException {

ObjectInputStream in= new ObjectInputStream(newBufferedInputStream(new FileInputStream("students.dat")));try{int size =in.readInt();

List list = new ArrayList<>(size);for(int i = 0; i < size; i++) {

list.add((Student) in.readObject());

}returnlist;

}finally{

in.close();

}

}

二)定制序列化

主要有两种定制序列化的机制:

1)使用transient关键字

声明为transient的字段,Java的默认序列化机制就不会保存该字段了,

但可以通过writeObject来自己保存。

2)实现writeObject和readObject方法

writeObject声明必须为:

private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException

ArrayList中有:

private voidwriteObject(java.io.ObjectOutputStream s)throwsjava.io.IOException{//Write out element count, and any hidden stuff

int expectedModCount =modCount;//该方法必须被调用,即使类中所有的字段都是transient

s.defaultWriteObject();//Write out size as capacity for behavioural compatibility with clone()

s.writeInt(size);//Write out all elements in the proper order.

for (int i=0; i

s.writeObject(elementData[i]);

}if (modCount !=expectedModCount) {throw newConcurrentModificationException();

}

}

readObject方法必须声明为:

private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException

private voidreadObject(java.io.ObjectInputStream s)throwsjava.io.IOException, ClassNotFoundException {

elementData=EMPTY_ELEMENTDATA;//Read in size, and any hidden stuff

s.defaultReadObject();//Read in capacity

s.readInt(); //ignored

if (size > 0) {//be like clone(), allocate array based upon size not capacity

ensureCapacityInternal(size);

Object[] a=elementData;//Read in all elements in the proper order.

for (int i=0; i

a[i]=s.readObject();

}

}

}

三)基本逻辑

writeObject基本逻辑:

1)如果对象没有实现Serializable,抛出NotSerializable异常

2)每个对象都有一个编号,如果之前已经写过该对象,下次写入只会写该

对象的引用,这可以解决对象引用和循环引用的问题

3)如果对象实现了writeObject方法,调用它的自定义方法

4)利用的是反射机制

readObject基本逻辑:

1)不调用任何构造方法

2)它自己就相当于一个独立的构造方法,根据字节流初始化对象,利用的也是反射机制

3)在解析流时,对于引用到的类型信息会动态加载,如果找不到,抛出ClassNotFoundException

四)版本问题

需要解决的问题:序列化到文件的对象是持久保存的,不会自己改变的,而我们

的代码是不断演变改进的,如果类的定义发生了变化,反序列化会出现问题。

解决方法:Java会给类自动定义一个版本号,这个版本号是根据类中的信息生成的。

在反序列化时,如果类的定义发生了变化,版本号就会变化,与流中的版本号就会

不匹配,反序列化就会抛出java.in.InvalidClassException.

但因为Java自动生成版本号性能较低,还有为了更好地控制,我们通常自定义这个

版本号。注意通过编辑器自动生成的版本号不会自己更新。

如果版本号一样,但实际字段不匹配:

1)字段删除了:即使流中有该字段,类定义中有,该字段会被忽略;

2)新增了字段:即类定义中有,而流中没有,该字段会被设置为默认值;

3)字段类型改变:抛出InvalidClassException;

五、使用Jackson序列化

一)基本用法

1.JSON

Student student = new Student("ୟӣ", 18, 80.9d);//它是一个线程安全类

ObjectMapper mapper = newObjectMapper();

mapper.enable(SerializationFeature.INDENT_OUTPUT);//默认情况下会保存所有声明为public或者有public getter方法的字段

String str =mapper.writeValueAsString(student);

System.out.println(str);

ObjectMapper mapper = newObjectMapper();//默认情况下,被反序列化的类必须要有无参构造函数

Student s = mapper.readValue(new File("student.json"), Student.class);

System.out.println(s.toString());

其他重要方法:

public byte[] writeValueAsBytes(Object value)public voidwriteValue(OutputStream out, Object value)public voidwriteValue(Writer w, Object value)public voidwriteValue(File resultFile, Object value)public T readValue(InputStream src, ClassvalueType)public T readValue(Reader src, ClassvalueType)public T readValue(String content, ClassvalueType)public T readValue(byte[] src, Class valueType)

2.XML

与序列化为JSON类似:

Student student = new Student("tom", 18, 80.9d);

ObjectMapper mapper= newXmlMapper();

mapper.enable(SerializationFeature.INDENT_OUTPUT);

String str=mapper.writeValueAsString(student);

mapper.writeValue(new File("student.xml"), student);

System.out.println(str);

3.MessagePack

MessagePack是一种二进制形式的JSON编码更为精简高效,因为是二进制,因此不能写出为String。

Student student = new Student("jim", 18, 80.9d);

ObjectMapper mapper= new ObjectMapper(newMessagePackFactory());byte[] bytes =mapper.writeValueAsBytes(student);

mapper.writeValue(new File("student.bson"), student);

Student s= mapper.readValue(new File("student.bson"), Student.class);

System.out.println(s.toString())

4.容器对象

List students = Arrays.asList(newStudent[] {new Student("tom", 18, 80.9d), new Student("๫ ",ࢥ17, 67.5d) });

ObjectMapper mapper= newObjectMapper();

mapper.enable(SerializationFeature.INDENT_OUTPUT);

String str=mapper.writeValueAsString(students);

mapper.writeValue(new File("students.json"), students);

System.out.println(str);//反序列化不同,需要新建一个TypeReference对象

List list = mapper.readValue(new File("students.json"),new TypeReference>() {});

System.out.println(list.toString());

二)定制序列化

1.忽略字段

//用于字段,getter、setter方法

@JsonIgnoredouble score;

//用于类,指定忽略字段

@JsonIgnoreProperties("score")public class Student {

2.引用同一个对象

问题:

Dog price = new Dog("Price");

Person jim= new Person("Jim", price, price);

ObjectMapper mapper= newObjectMapper();

mapper.enable(SerializationFeature.INDENT_OUTPUT);

String value=mapper.writeValueAsString(jim);

System.out.println(value);

Person person= mapper.readValue(value, Person.class);if (person.getFirst() ==person.getSecond()) {

System.out.println("Same");

}else{

System.out.println("Different"); //different 指向了不同的对象

}

解决办法:

@JsonIdentityInfo(

generator= ObjectIdGenerators.IntSequenceGenerator.class,

property= "id")public class Dog {

3.循环引用

问题:

Parent parent = newParent();

parent.name= "Father";

Child child= newChild();

child.name= "Child";

parent.child=child;

child.parent=parent;

ObjectMapper mapper= newObjectMapper();

mapper.enable(SerializationFeature.INDENT_OUTPUT);

String s= mapper.writeValueAsString(parent); //java.lang.StackOverflowError

System.out.println(s);

解决办法:

public classParent {publicString name;

@JsonManagedReference//标记为主引用

publicChild child;

}public classChild {publicString name;

@JsonBackReference//标记为反向引用

publicParent parent;

}

4.反序列化时忽略未知字段

问题:与Java标准序列化不同,在反序列化时,对于未知字段,Jackson默认会抛出异常:UnrecognizedPropertyException.

解决办法:

mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

或者:

@JsonIgnoreProperties(ignoreUnknown=true)public classStudent {//...

}

5.继承和多态

Jackson不能自动处理继承和多态:

public classShape {

}public class Circle extendsShape {private intr;publicCircle() {

}public Circle(intr) {this.r =r;

}

}public class Square extendsShape {private intl;publicSquare() {

}public Square(intl) {this.l =l;

}

}

public classShapeManager {private ListshapeList;public ListgetShapeList() {returnshapeList;

}public void setShapeList(ListshapeList) {this.shapeList =shapeList;

}

}

解决办法:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")

@JsonSubTypes({

@JsonSubTypes.Type(value= Circle.class, name = "circle"),

@JsonSubTypes.Type(value= Square.class, name = "square")

})public classShape {

}

6.修改字段名称

@JsonProperty("名称:") //改变输出

String name;

//对于xml修改根元素名称

@JsonRootName("student")public class Student {

7.格式化日期

默认情况下日期会被序列化为一个长整数。解决:

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")public Date date = new Date();

8.配置构造方法

序列化时,如果类没有无参构造函数,会抛异常。解决:

@JsonCreatorpublicStudent(

@JsonProperty("name") String name,

@JsonProperty("age") intage,

@JsonProperty("score") doublescore) {this.name =name;this.age =age;this.score =score;

}