Java file segmented upload, download, preview interface

Multiple upload

private Map<String, List<File>> chunksMap = new ConcurrentHashMap<>();
public void upload(PartFile fileInfo, MultipartFile chunk) {<!-- -->
//
        int currentChunk = fileInfo.getCurrentChunk();
        int totalChunks = fileInfo.getTotalChunks();
        String fileName = fileInfo.getFileName();
        String chunkName = chunk.getOriginalFilename() + '.' + currentChunk;
        File chunkFile = new File(uploadCachePath, chunkName);
        try (BufferedInputStream bis = new BufferedInputStream(chunk.getInputStream());
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(chunkFile))) {<!-- -->
            byte[] buffer = new byte[1024];
            int i;
            while ((i = bis.read(buffer)) != -1) {<!-- -->
                bos.write(buffer, 0, i);
            }
            bos.flush();
        } catch (IOException e) {<!-- -->
            e.printStackTrace();
            throw new RuntimeException('Sharded file writing exception');
        }
        List<File> chunkList = chunksMap.computeIfAbsent(fileName, k -> new ArrayList<>(totalChunks));
        chunkList.add(chunkFile);
    }

1. Obtain the current fragment index (currentChunk), total number of fragments (totalChunks), and file name (fileName) based on the file information (PartFile).

2. Construct the file name (chunkName) of the current shard, and connect the original file name and the current shard index to form a new file name.

3. Create a File object (chunkFile) for writing the current fragment file, which is located at the specified upload cache path and built file name.

4. Use BufferedInputStream and BufferedOutputStream to create input and output stream objects respectively, which are used to read the contents of the fragmented file and write it to the specified file.

5. Loop to read the data in bis (slice file input stream) into the buffer byte array, return the actual number of bytes read i, and return -1 if the end of the file is read.

6. Write the bytes from 0 to i in the buffer to bos (slice file output stream).

7. Repeat steps 5 and 6 until the entire fragmented file is read.

8. Refresh and close bos to ensure that the data is written to the disk.

9. If an IOException occurs during file writing, print the exception information and throw a RuntimeException.

10. Obtain the fragment file list (chunkList) corresponding to the current file name (fileName) from chunksMap. If the fragment file list does not exist, create an empty ArrayList through computeIfAbsent and associate it with the current file name.

11. Add the currently written chunk file (chunkFile) to the chunk file list for merging.

Shard merging

public String merge(String uploadPath, String fileName) throws IOException {<!-- -->
        List<File> chunkList = chunksMap.get(fileName);
        if (chunkList == null || chunkList.size() == 0) {<!-- -->
            throw new RuntimeException('Shard does not exist');
        }
        File outputFile = new File(uploadPath + '/' + fileName);
        if (!outputFile.getParentFile().exists()) outputFile.getParentFile().mkdirs();
        if (!outputFile.exists()) outputFile.createNewFile();
        try (FileChannel outChannel = new FileOutputStream(outputFile).getChannel()) {<!-- -->
            for (File file : chunkList) {<!-- -->
                try (FileChannel inChannel = new FileInputStream(file).getChannel()) {<!-- -->
                    inChannel.transferTo(0, inChannel.size(), outChannel);
                }
                file.delete();
            }
        }
        chunksMap.remove(fileName);
        return outputFile.getCanonicalPath();
    }

1. This code is a method for merging file fragments. It receives two parameters: uploadPath is the path to upload the file, and fileName is the name of the file to be merged.

2. First, the code obtains the chunkList corresponding to the file fragments through chunksMap. If the chunkList is empty or does not have any fragments, a runtime exception will be thrown, prompting “the fragment does not exist”.

3. Next, the code creates an output file object outputFile with the path uploadPath + /’ + fileName. If the parent directory of the output file does not exist, the directory is created. If the output file itself does not exist, a new, empty file is created.

4. Then, use the try-with-resources statement to open an output file channel outChannel, and associate the output file with the channel through FileOutputStream. Then start looping through each file in the chunkList.

5. In each loop, the code opens an input file channel inChannel and associates the current fragmented file with the input channel through FileInputStream. Then use the inChannel.transferTo() method to transfer the contents of the input channel to the output channel outChannel to merge the file contents.

6. After completing a merge, the code deletes the current shard file.

7. After the loop ends, the code removes the fragment list of the current file from the chunksMap.

8. Finally, the code returns the merged file path, which is the canonical path of the output file.

It should be noted that IOException is thrown in the code, so you need to handle the exception that may be thrown when calling this method.

Download

public void download(HttpServletResponse response, String path) {<!-- -->
        File file = new File(path);
        response.setHeader('Access-Control-Allow-Origin', '*');
        response.setHeader('Content-Disposition', 'attachment;filename=' + file.getName());
        response.setContentType('application/octet-stream;charset=UTF-8');
        response.setHeader('Access-Control-Expose-Headers', 'Content-Disposition,application/octet-stream');
        if (!file.exists() || file.isDirectory()) throw new RuntimeException('The file does not exist or the format does not support downloading');
        try (BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
             FileChannel channel = new FileInputStream(file).getChannel()) {<!-- -->
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (channel.read(buffer) != -1) {<!-- -->
                buffer.flip();
                bos.write(buffer.array(), 0, buffer.limit());
                buffer.clear();
            }
            bos.flush();
        } catch (Exception e) {<!-- -->
            e.printStackTrace();
        }
    }

1. This code is a method for file downloading. It receives two parameters: response is the HTTP response object, and path is the path of the file to be downloaded.

2. The code first creates a file object file based on the file path. Then set some parameters in the HTTP response header, including allowing cross-domain access, setting the file name, setting the content type, etc.

3. Then, if the file does not exist or is a directory, a runtime exception will be thrown, prompting “the file does not exist or the format does not support downloading”.

4. Finally, the code uses the try-with-resources statement to open an output stream bos and an input channel channel. The output stream is associated with the output stream of the response object so that the contents of the file can be returned to the client through an HTTP response; the input channel is associated with the file object so that data can be read from the file.

5. Inside a loop, the code uses a ByteBuffer object to temporarily store the data read from the input channel each time, determines whether the end of the file has been read, and if not, writes the data to the output stream, and then clears the ByteBuffer for the next read. Get data. Finally, the output stream is refreshed and all data in the buffer is sent to the client.

It should be noted that some parameters in the HTTP response header must be set, otherwise the download will not be successful.

Preview image

public ResponseEntity<byte[]> previewImage(String path) throws IOException {<!-- -->
        File imageFile = new File(path);
        byte[] imageData = new byte[(int) imageFile.length()];
        FileInputStream fis = new FileInputStream(imageFile);
        int byteRead = fis.read(imageData);
        fis.close();

        String formatName = null;
        try(MemoryCacheImageInputStream inputStream = new MemoryCacheImageInputStream(new ByteArrayInputStream(imageData))) {<!-- -->
            Iterator<ImageReader> iterator = ImageIO.getImageReaders(inputStream);
            if (iterator.hasNext()) {<!-- -->
                ImageReader reader = iterator.next();
                formatName = reader.getFormatName();
            }
        }
        HttpHeaders headers = new HttpHeaders();
        if (formatName != null) {<!-- -->
            headers.setContentType(MediaType.parseMediaType('image/' + formatName.toLowerCase()));
        }
        return new ResponseEntity<>(imageData, headers, HttpStatus.OK);
    }
}

1. This code is a method for previewing images. It receives a path parameter, indicating the path of the image file, and returns a ResponseEntity object.

2. The code first creates a File object imageFile based on the image file path, and then creates a byte array imageData of the corresponding size based on the file size.

3. Next, the code reads the content of the image file through FileInputStream and saves it to the byte array imageData. After reading, close the input stream.

4. After that, the code uses MemoryCacheImageInputStream to wrap the byte array imageData, and obtains the format of the image file through ImageIO.getImageReaders(). If the image format is successfully obtained, assign it to formatName.

5. Next, the code creates an HttpHeaders object headers, which is used to set response header information. If the image format formatName is successfully obtained, set the response Content-Type to the corresponding media type.

6. Finally, the code uses ResponseEntity to encapsulate the byte array imageData, response headers and HttpStatus.OK status code, and returns the object.

It should be noted that a converter that supports images must be added to the message converter of webMvc.

//Support image preview
ByteArrayHttpMessageConverter byteArrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.IMAGE_JPEG);
mediaTypes.add(MediaType.IMAGE_PNG);
mediaTypes.add(MediaType.IMAGE_GIF);
byteArrayHttpMessageConverter.setSupportedMediaTypes(mediaTypes);
converters.add(byteArrayHttpMessageConverter);