All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.io.IOWriteUtil Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.feilong.io;

import static com.feilong.core.CharsetType.UTF8;
import static com.feilong.core.date.DateUtil.formatDuration;
import static com.feilong.core.date.DateUtil.now;
import static com.feilong.core.lang.ObjectUtil.defaultIfNullOrEmpty;
import static com.feilong.io.entity.FileWriteMode.COVER;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.feilong.core.CharsetType;
import com.feilong.core.Validate;
import com.feilong.io.entity.FileWriteMode;

/**
 * 专注于写文件的操作的工具类.
 * 
 * 
    *
  • {@link #write(InputStream, OutputStream)} 写资源,速度最快的方法,速度比较请看 电脑资料 {@code <<压缩解压性能探究>>}
  • *
  • {@link #write(InputStream, String, String)} 将inputStream 写到 某个文件夹,名字为fileName
  • *
  • {@link #writeStringToFile(String, String, String)} 将字符串/文字写到文件中
  • *
  • {@link #writeStringToFile(String, String, String, FileWriteMode)} 将字符串写到文件中
  • *
* * 如果需要覆盖写文件,可以调用 {@link #writeStringToFile(String, String, String, FileWriteMode)}. * * @author feilong * @see "org.springframework.util.StreamUtils" * @see "org.springframework.util.FileCopyUtils" * @see com.feilong.lib.io.IOUtils * @since 1.0.6 */ public final class IOWriteUtil{ /** The Constant LOGGER. */ private static final Logger LOGGER = LoggerFactory.getLogger(IOWriteUtil.class); /** 默认缓冲大小 10k {@value}. */ public static final int DEFAULT_BUFFER_LENGTH = (int) (10 * FileUtil.ONE_KB); //--------------------------------------------------------------- /** Don't let anyone instantiate this class. */ private IOWriteUtil(){ //AssertionError不是必须的. 但它可以避免不小心在类的内部调用构造器. 保证该类在任何情况下都不会被实例化. //see 《Effective Java》 2nd throw new AssertionError("No " + getClass().getName() + " instances for you!"); } //--------------------------------------------------------------- /** * 将字符串/文字写到文件中. * *

相关规则:

* *
*
    *
  • 如果 filePath 是null,抛出 {@link NullPointerException}
  • *
  • 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
  • *
  • 如果文件不存在,自动创建,包括其父文件夹 (支持级联创建 文件夹)
  • *
  • 如果文件存在则覆盖旧文件,可以设置{@link FileWriteMode#APPEND}表示追加内容而非覆盖
  • *
  • 默认使用{@link CharsetType#UTF8}编码
  • *
*
* * @param filePath * 文件路径 * @param content * 字符串内容 * @see FileWriteMode * @see CharsetType * @see #writeStringToFile(String, String, String, FileWriteMode) * @see "com.feilong.lib.io.FileUtils#writeStringToFile(File, String, Charset)" * @since 3.0.4 */ public static void writeStringToFile(String filePath,String content){ writeStringToFile(filePath, content, UTF8, COVER); } /** * 将字符串/文字写到文件中. * *

相关规则:

* *
*
    *
  • 如果 filePath 是null,抛出 {@link NullPointerException}
  • *
  • 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
  • *
  • 如果文件不存在,自动创建,包括其父文件夹 (支持级联创建 文件夹)
  • *
  • 如果文件存在则覆盖旧文件,可以设置{@link FileWriteMode#APPEND}表示追加内容而非覆盖
  • *
  • 如果不设置 charsetType,则默认使用{@link CharsetType#UTF8}编码
  • *
*
* * @param filePath * 文件路径 * @param content * 字符串内容 * @param charsetType * 字符编码,建议使用 {@link CharsetType} 定义好的常量,如果isNullOrEmpty,则默认使用 {@link CharsetType#UTF8}编码 {@link CharsetType} * @see FileWriteMode * @see CharsetType * @see #writeStringToFile(String, String, String, FileWriteMode) * @see "com.feilong.lib.io.FileUtils#writeStringToFile(File, String, Charset)" * @since 1.5.4 */ public static void writeStringToFile(String filePath,String content,String charsetType){ writeStringToFile(filePath, content, charsetType, COVER);//default_fileWriteMode } //--------------------------------------------------------------- /** * 将字符串写到文件中. * *

* (注意,本方法最终会关闭 inputStream以及 outputStream). *

* *

相关规则:

* *
*
    *
  • 如果 filePath 是null,抛出 {@link NullPointerException}
  • *
  • 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
  • * *
  • 如果文件不存在,自动创建,包括其父文件夹 (支持级联创建 文件夹)
  • *
  • 如果文件存在则覆盖旧文件,可以设置{@link FileWriteMode#APPEND}表示追加内容而非覆盖
  • *
  • 如果不设置 charsetType,则默认使用{@link CharsetType#UTF8}编码
  • *
*
* * @param filePath * 文件路径 * @param content * 字符串内容 * @param charsetType * 字符编码,建议使用 {@link CharsetType} 定义好的常量,如果isNullOrEmpty,则默认使用 {@link CharsetType#UTF8}编码 * @param fileWriteMode * 写模式 {@link FileWriteMode} * @see java.io.FileOutputStream#FileOutputStream(File, boolean) * @see #write(InputStream, OutputStream) * @see com.feilong.lib.io.FileUtils#writeStringToFile(File, String, Charset, boolean) * @since 1.5.4 */ public static void writeStringToFile(String filePath,String content,String charsetType,FileWriteMode fileWriteMode){ Validate.notBlank(filePath, "filePath can't be null/empty!"); //--------------------------------------------------------------- Date beginDate = now(); String useEncode = defaultIfNullOrEmpty(charsetType, UTF8); FileWriteMode useFileWriteMode = defaultIfNullOrEmpty(fileWriteMode, COVER); //--------------------------------------------------------------- FileUtil.createDirectoryByFilePath(filePath); //--------------------------------------------------------------- InputStream inputStream = InputStreamUtil.newByteArrayInputStream(content, useEncode); OutputStream outputStream = FileUtil.getFileOutputStream(filePath, useFileWriteMode); //--------------------------------------------------------------- write(inputStream, outputStream); //--------------------------------------------------------------- if (LOGGER.isInfoEnabled()){ File file = new File(filePath); String size = FileUtil.getFileFormatSize(file); String pattern = "fileWriteMode:[{}],encode:[{}],contentLength:[{}],fileSize:[{}],absolutePath:[{}],time:[{}]"; String useTime = formatDuration(beginDate); LOGGER.info(pattern, useFileWriteMode, useEncode, content.length(), size, file.getAbsolutePath(), useTime); } } //--------------------------------------------------------------- /** * 将inputStream 写到某个文件夹 directoryPath ,名字为 fileName. * *

* (注意,本方法最终会关闭 inputStream以及 outputStream). *

* *

* 如果拼接完的文件路径,父路径不存在,则自动创建(支持级联创建文件夹) *

* *

说明:

* *
*

* 支持 fileName 是路径的写法: *

* *
     * IOWriteUtil.write(getInputStream(), "/Users/feilong/logs/","a/a.txt");
     * 
* *

* 此时会将内容写到 /Users/feilong/logs/a/a.txt 文件 *

* *
* *

* 也支持 fileName 带相对路径的写法: *

* *
     * IOWriteUtil.write(getInputStream(), "/Users/feilong/logs/","../a/a.txt");
     * 
* *

* 此时会将内容写到 /Users/feilong/a/a.txt 文件 *

* *
* * @param inputStream * 上传的文件流 * @param directoryPath * 文件夹路径, 支持格式类似于是 /Users/feilong/logs/ 或者 /Users/feilong/logs * @param fileName * 文件名称 * @return 如果 inputStream 是null,抛出 {@link NullPointerException}
* 如果 directoryPath 是null,抛出 {@link NullPointerException}
* 如果 directoryPath 是blank,抛出 {@link IllegalArgumentException}
* 如果 fileName 是null,抛出 {@link NullPointerException}
* 如果 fileName 是blank,抛出 {@link IllegalArgumentException}
* 否则返回新文件全路径 * @see #write(InputStream, OutputStream) * @since 3.0.0 change return type from void to String */ public static String write(InputStream inputStream,String directoryPath,String fileName){ Validate.notNull(inputStream, "inputStream can't be null!"); Validate.notBlank(directoryPath, "directoryPath can't be blank!"); Validate.notBlank(fileName, "fileName can't be blank!"); //--------------------------------------------------------------- Date beginDate = now(); //--------------------------------------------------------------- //since 1.12.9 Path path = Paths.get(directoryPath, fileName).normalize(); String filePath = path.toString(); //--------------------------------------------------------------- if (LOGGER.isDebugEnabled()){ LOGGER.debug("directoryPath:[{}],fileName:[{}] ==> file final Path:[{}]", directoryPath, fileName, filePath); } //--------------------------------------------------------------- FileUtil.createDirectoryByFilePath(filePath); OutputStream outputStream = FileUtil.getFileOutputStream(filePath); write(inputStream, outputStream); //--------------------------------------------------------------- if (LOGGER.isInfoEnabled()){ File file = new File(filePath); String messagePattern = "fileSize:[{}],absolutePath:[{}],use time:[{}]"; LOGGER.info(messagePattern, FileUtil.getFileFormatSize(file), file.getAbsolutePath(), formatDuration(beginDate)); } return filePath; } //--------------------------------------------------------------- /** * 写资源,速度最快的方法,速度比较请看 电脑资料 {@code <<压缩解压性能探究>>}. * *

* (注意,本方法最终会关闭 inputStream以及 outputStream). *

* *

* Just write in blocks instead of copying it entirely into Java's memory first.
* The below basic example writes it in blocks of 10KB.
* This way you end up with a consistent memory usage of only 10KB instead of the complete content length.
* Also the enduser will start getting parts of the content much sooner. *

* * @param inputStream * inputStream * @param outputStream * outputStream * @see java.io.OutputStream#write(byte[], int, int) * @see #write(InputStream, OutputStream,int) * @see com.feilong.lib.io.IOUtils#copyLarge(InputStream, OutputStream) */ public static void write(InputStream inputStream,OutputStream outputStream){ write(inputStream, outputStream, DEFAULT_BUFFER_LENGTH); } //--------------------------------------------------------------- /** * 写资源,速度最快的方法,速度比较请看电脑资料 {@code <<压缩解压性能探究>>} . * *

* (注意,本方法最终会关闭 inputStream以及 outputStream). *

* *

* 如果 inputStream 是null,抛出 {@link NullPointerException}
* 如果 outputStream 是null,抛出 {@link NullPointerException}
*

* * @param inputStream * inputStream * @param outputStream * outputStream * @param bufferLength * 每次循环buffer大小 ,必须 {@code >}0 * @see #writeUseNIO(InputStream, OutputStream,int) * @see java.io.OutputStream#write(byte[], int, int) * @see com.feilong.lib.io.IOUtils#copyLarge(InputStream, OutputStream) * @see com.feilong.lib.io.IOUtils#copy(InputStream, OutputStream, int) * @see As creme de la creme with * regard to performance, you could use NIO Channels and ByteBuffer. Create the following utility/helper method in some custom * utility class, */ public static void write(InputStream inputStream,OutputStream outputStream,int bufferLength){ writeUseNIO(inputStream, outputStream, bufferLength); } //--------------------------------------------------------------- /** * 使用NIO API 来写数据 (效率高). * *

* (注意,本方法最终会关闭 inputStream以及 outputStream). *

* *

关于NIO

* *
*

* nio是new io的简称,从jdk1.4就被引入了,可以说不是什么新东西了.
* nio的主要作用就是用来解决速度差异的.
*

* *

* 举个例子:计算机处理的速度,和用户按键盘的速度.这两者的速度相差悬殊.
* 如果按照经典的方法:一个用户设定一个线程,专门等待用户的输入,无形中就造成了严重的资源浪费 :每一个线程都需要珍贵的cpu时间片,由于速度差异造成了在这个交互线程中的cpu都用来等待.
* 在以前的 Java IO 中,都是阻塞式 IO,NIO 引入了非阻塞式 IO. *

* *

* The new I/O (NIO) APIs introduced in v 1.4 provide new features and improved performance in the areas of buffer management, scalable * network and file I/O, character-set support, and regular-expression matching. The NIO APIs supplement the I/O facilities in the * java.io package. *

* *

* The NIO APIs include the following features: *

* *
    *
  1. Buffers for data of primitive types
  2. *
  3. Character-set encoders and decoders
  4. *
  5. A pattern-matching facility based on Perl-style regular expressions
  6. *
  7. Channels, a new primitive I/O abstraction
  8. *
  9. A file interface that supports locks and memory mapping
  10. *
  11. A multiplexed, non-blocking I/O facility for writing scalable servers
  12. *
*
* *

* As creme de la creme with regard to performance,you could use NIO {@link java.nio.channels.Channels} and {@link java.nio.ByteBuffer}. *

* *

* 如果 inputStream 是null,抛出 {@link NullPointerException}
* 如果 outputStream 是null,抛出 {@link NullPointerException}
*

* * @param inputStream * the input stream * @param outputStream * the output stream * @param bufferLength * the buffer length * @since 1.0.8 * @since jdk1.4 */ private static void writeUseNIO(InputStream inputStream,OutputStream outputStream,int bufferLength){ Validate.notNull(inputStream, "inputStream can't be null!"); Validate.notNull(outputStream, "outputStream can't be null!"); //--------------------------------------------------------------- Date beginDate = now(); int loopCount = 0; int sumSize = 0; ByteBuffer byteBuffer = ByteBuffer.allocate(bufferLength); try (ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream); WritableByteChannel writableByteChannel = Channels.newChannel(outputStream);){ while (readableByteChannel.read(byteBuffer) != IOUtil.EOF){ byteBuffer.flip(); sumSize += writableByteChannel.write(byteBuffer); byteBuffer.clear(); loopCount++; } //--------------------------------------------------------------- if (LOGGER.isDebugEnabled()){ String pattern = "Write data over,sumSize:[{}],bufferLength:[{}],loopCount:[{}],use time:[{}]"; LOGGER.debug(pattern, FileUtil.formatSize(sumSize), bufferLength, loopCount, formatDuration(beginDate)); } }catch (IOException e){ throw new UncheckedIOException(e); }finally{ IOUtil.closeQuietly(outputStream, inputStream); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy