user2558093
user2558093

Reputation: 33

Java download file excel problems

I have developed a code for downloading excel file from server.

Downloading a.xlsx file gives "We found a problem with some content in 'FileName.xlsx'.Do you want us to try to recover as much as we can? If you trust the source of this workbook, Click Yes". On clicking "Yes" button, it displays content. I am able to open the file after it is repaired and the data seems to be fine. Error shows for both Open and save options. But after repair data is still there. The is no error on opening the file in server.

Is anything I need to do?

public void downloadFile(String fileName, String filePath) {
    try {
        fileName = URLEncoder.encode(fileName,"UTF-8");
    } catch (UnsupportedEncodingException e1) {
        logger.info("Can not encode file name");
    } 
    response.setContentType("application/octet-stream; charset=UTF-8");
    response.setHeader("Content-Disposition", "attachment;filename="
        + fileName);
        response.setCharacterEncoding("UTF-8");
    try {
        ServletOutputStream out = response.getOutputStream();
        FileInputStream in = new FileInputStream(new File(filePath));
        byte[] outputByte = new byte[4096];
        while (in.read(outputByte, 0, 4096) != -1) {
            out.write(outputByte, 0, 4096);
        }
        in.close();
        out.flush();
        out.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Upvotes: 1

Views: 2287

Answers (3)

Elizabeth R
Elizabeth R

Reputation: 1

Even I was stuck with this issue for about 1 week. Finally, I resolved the issue and got an excel output without being corrupted by using the below code.

I did it as a maven project.

Add the following dependency for Super CSV Core » 2.4.0 in your pom.xml file

 <!-- https://mvnrepository.com/artifact/net.sf.supercsv/super-csv -->
<dependency>
    <groupId>net.sf.supercsv</groupId>
    <artifactId>super-csv</artifactId>
    <version>2.4.0</version>
</dependency>

Now use the below code for your controller class

CSVFileDownloadController.java

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.supercsv.io.CsvBeanWriter;
import org.supercsv.io.ICsvBeanWriter;
import org.supercsv.prefs.CsvPreference;

import com.rapidvalue.master.employee.vo.Book;

@Controller
public class CSVFileDownloadController {
      @RequestMapping(value = "/downloadCSV")
        public void downloadCSV(HttpServletResponse response) throws IOException {

            String csvFileName = "books.csv";

            response.setContentType("text/csv");

            // creates mock data
            String headerKey = "Content-Disposition";
            String headerValue = String.format("attachment; filename=\"%s\"",
                    csvFileName);
            response.setHeader(headerKey, headerValue);

            Book book1 = new Book("Effective Java", "Java Best Practices",
                    "Joshua Bloch", "Addision-Wesley", "0321356683", "05/08/2008",
                    38);

            Book book2 = new Book("Head First Java", "Java for Beginners",
                    "Kathy Sierra & Bert Bates", "O'Reilly Media", "0321356683",
                    "02/09/2005", 30);

            Book book3 = new Book("Thinking in Java", "Java Core In-depth",
                    "Bruce Eckel", "Prentice Hall", "0131872486", "02/26/2006", 45);

            Book book4 = new Book("Java Generics and Collections",
                    "Comprehensive guide to generics and collections",
                    "Naftalin & Philip Wadler", "O'Reilly Media", "0596527756",
                    "10/24/2006", 27);

            List<Book> listBooks = Arrays.asList(book1, book2, book3, book4);

            // uses the Super CSV API to generate CSV data from the model data
            ICsvBeanWriter csvWriter = new CsvBeanWriter(response.getWriter(),
                    CsvPreference.STANDARD_PREFERENCE);

            String[] header = { "Title", "Description", "Author", "Publisher",
                    "isbn", "PublishedDate", "Price" };

            csvWriter.writeHeader(header);

            for (Book aBook : listBooks) {
                csvWriter.write(aBook, header);
            }

            csvWriter.close();
        }
    }

Use this as your model data class

Book.java

public class Book {
    private String title;
    private String description;
    private String author;
    private String publisher;
    private String isbn;
    private String publishedDate;
    private float price;

    public Book() {
    }

    public Book(String title, String description, String author, String publisher,
            String isbn, String publishedDate, float price) {
        this.title = title;
        this.description = description;
        this.author = author;
        this.publisher = publisher;
        this.isbn = isbn;
        this.publishedDate = publishedDate;
        this.price = price;
    }

    // getters and setters...
}

Now run this code on the server. Hit the URL in the browser. Your file will be downloaded without any issue. Hope this will help! :)

Upvotes: 0

Dariusz
Dariusz

Reputation: 22241

byte[] outputByte = new byte[4096];
while (in.read(outputByte, 0, 4096) != -1) {
      out.write(outputByte, 0, 4096);
}

In this code you always write 4096 bytes. For your last chunk of data you write more data than was read (at least 4095 out of 4096 times).

You have to check the amount read and write exactly the read amount to outputstream.

int readAmount= 0;
int arrLen = 4096;
byte[] outputByte = new byte[arrLen];
while ((readAmount = in.read(outputByte, 0, arrLen)) != -1) {
      out.write(outputByte, 0, readAmount);
}

Upvotes: 0

Giovanni
Giovanni

Reputation: 4015

The problem lies here

 while (in.read(outputByte, 0, 4096) != -1) {
     out.write(outputByte, 0, 4096);
 }

when you reach the end of the file you are not rading 4096 but something less. You must save how much data you read and write to the output: something like

 int bytesRead=0;
 while ((bytesRead=in.read(outputByte, 0, 4096)) != -1) {
     out.write(outputByte, 0, bytesRead);
 }

Upvotes: 3

Related Questions