文件上传MultipartFile的getInputStream方法返回不同流对象问题

java文件上传的时候发现CommonsMultipartFile的getInputStream方法在文件不同大小的时候返回的流对象是不同的,导致CommonsMultipartFile.getInputStream()方法在转换为对应的子类对象是报错,当时很是纠结,然后看了下getInputStream的代码实现

结论:

  • 当文件小于10240b(即10kb)的时候,返回的是ByteArrayInputStream
  • 当文件大于10kb的时候,返回的FileInputStream

源码实现:

下面看一下具体的内部实现:

	@Override
	public InputStream getInputStream() throws IOException {
		if (!isAvailable()) {
			throw new IllegalStateException("File has been moved - cannot be read again");
		}
		// 实际返回的对象是 成员变量fileItem返回的
		InputStream inputStream = this.fileItem.getInputStream();
		return (inputStream != null ? inputStream : StreamUtils.emptyInput());
	}

成员变量FileItem的具体实现子类是DiskFileItem,下面是DiskFileItem的getInputStream:

	public InputStream getInputStream()
        throws IOException {
        // 判断文件的大小是
        if (!isInMemory()) {
            return new FileInputStream(dfos.getFile());
        }

        if (cachedContent == null) {
            cachedContent = dfos.getData();
        }
        return new ByteArrayInputStream(cachedContent);
    }

isInMemory方法的具体实现:

	public boolean isInMemory() {
        if (cachedContent != null) {
            return true;
        }
        // 继续判断
        return dfos.isInMemory();
    }
    
	public boolean isInMemory()
    {
        return !isThresholdExceeded();
    }
    
 	public boolean isThresholdExceeded()
    {
    	// 最终的判断逻辑  written指的是上传的文件的大小,threshold是判断文件大小的标准
        return written > threshold;
    }

接下来我们需要看一下threshold是在什么地方进行赋值的:

	// 构造方法传值
	public ThresholdingOutputStream(int threshold)
    {
        this.threshold = threshold;
    }
	
	// DeferredFileOutputStream是ThresholdingOutputStream的子类
	private DeferredFileOutputStream(int threshold, File outputFile, String prefix, String suffix, File directory) {
		// 当DeferredFileOutputStream进行构造初始化的时候,首先会调用父类的构造方法
        super(threshold);
        this.outputFile = outputFile;

        memoryOutputStream = new ByteArrayOutputStream();
        currentOutputStream = memoryOutputStream;
        this.prefix = prefix;
        this.suffix = suffix;
        this.directory = directory;
    }
	
	public DeferredFileOutputStream(int threshold, File outputFile)
    {
        this(threshold,  outputFile, null, null, null);
    }
    	
	public OutputStream getOutputStream()
        throws IOException {
        if (dfos == null) {
            File outputFile = getTempFile();
            // DeferredFileOutputStream实例化的地方,成员变量threshold的值就是DiskFileItem的成员变量sizeThreshold的值,而sizeThreshold也是通过DiskFileItem的构造方法进行赋值的
            dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
        }
        return dfos;
    }
    
	public DiskFileItem(String fieldName,
            String contentType, boolean isFormField, String fileName,
            int sizeThreshold, File repository) {
        this.fieldName = fieldName;
        this.contentType = contentType;
        this.isFormField = isFormField;
        this.fileName = fileName;
        this.sizeThreshold = sizeThreshold;
        this.repository = repository;
    }
    
    // DiskFileItem的初始化是DiskFileItemFactory工厂实例化的,下面就是DiskFileItemFactory的createItem方法实现
	public FileItem createItem(String fieldName, String contentType,
            boolean isFormField, String fileName) {
        DiskFileItem result = new DiskFileItem(fieldName, contentType,
                isFormField, fileName, sizeThreshold, repository);
        FileCleaningTracker tracker = getFileCleaningTracker();
        if (tracker != null) {
            tracker.track(result.getTempFile(), result);
        }
        return result;
    }

我们整理一下具体的流程:

  1. DiskFileItemFactory.createItem
  2. DiskFileItem构造方法
  3. DiskFileItem的getOutputStream方法中会实例化DeferredFileOutputStream
  4. DeferredFileOutputStream构造方法中调用父类ThresholdingOutputStream构造方法

上面整个流程就是将DiskFileItemFactory成员变量sizeThreshold的值赋值给ThresholdingOutputStream成员变量threshold,那么DiskFileItemFactory中sizeThreshold的值是什么呢

   	private int sizeThreshold = DEFAULT_SIZE_THRESHOLD;
   	// 这里我们可以看到默认值就是10240b = 10kb
   	public static final int DEFAULT_SIZE_THRESHOLD = 10240;
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值