XSSFWorksheet duplicates the output after closing the file - java

I started working with Apache poi just recently. What I'm trying to do:
My method receives a HashMap, with the key being a long Vendor (a class I've created to represent a customer of my company) ID, and the value being the Vendor object itself.
My goal is to use the boolean attribute 'managed' in the Vendor object, and output into one file the list of managed Vendors (the ones that have 'true' in 'managed') and then another one for the unmanaged. Here's my code:
public static void loadVendorsIntoFile(XSSFWorkbook workbook, HashMap<Long,Vendor> vendors, boolean managed){
XSSFSheet vendorsSheet = workbook.createSheet("Vendors");
int rowNum = 1;
Row row = vendorsSheet.createRow(0);
row.createCell(0).setCellValue("vendor_id");
row.createCell(1).setCellValue("num_items");
row.createCell(2).setCellValue("vendor_username");
row.createCell(3).setCellValue("Segment");
row.createCell(4).setCellValue("AM");
for (long vendor : vendors.keySet()){
if (vendors.get(vendor) != null && vendors.get(vendor).getIfManaged() == managed){
row = vendorsSheet.createRow(rowNum);
row.createCell(0).setCellValue(vendors.get(vendor).getVendorId());
row.createCell(1).setCellValue(vendors.get(vendor).getCountItems());
row.createCell(2).setCellValue(vendors.get(vendor).getVendorName());
row.createCell(3).setCellValue(vendors.get(vendor).getSegment());
row.createCell(4).setCellValue(vendors.get(vendor).getAccountManager());
rowNum++;
}
}
}
public static void topvendorsOutput (HashMap<Long,Vendor> vendors) throws ClassNotFoundException, SQLException, IOException{
XSSFWorkbook managedWorkbook = new XSSFWorkbook();
loadVendorsIntoFile(managedWorkbook,vendors,true);
OutputStream outManaged = new FileOutputStream("C:\\Users\\User\\managed_out.xlsx");
managedWorkbook.write(outManaged);
outManaged.close();
XSSFWorkbook nonManagedWorkbook = new XSSFWorkbook();
loadVendorsIntoFile(nonManagedWorkbook,vendors,false);
OutputStream outNonManaged = new FileOutputStream("C:\\Users\\User\\unmanaged_out.xlsx");
managedWorkbook.write(outNonManaged);
outNonManaged.close();
}
However, for some reason I get two files with the same info - both show only managed Vendors. I've been testing (printing to the console) and I see that in the second call to loadVendorsIntoFile(), the unmanaged Vendors are really being printed when the loop runs - but for some reason the what is written to the second file is the info that should come only from the first call (and first file) to the method.
Also, the second call (which creates the second file) comes out with corruption problems, excel warns me that it has "found problems with the content" and needs to restore it.
I guess I'm doing something wrong here.
So in short - the first file is OK, the second one isn't.
Would appreciate any help with this. Thanks.

Looking at your code, we see a few problems:
XSSFWorkbook managedWorkbook = new XSSFWorkbook();
loadVendorsIntoFile(managedWorkbook,vendors,true);
OutputStream outManaged = new FileOutputStream("C:\\Users\\User\\unmanaged_out.xlsx");
managedWorkbook.write(outManaged);
outManaged.close();
This writes managedWorkbook into C:\\Users\\User\\unmanaged_out.xlsx
XSSFWorkbook nonManagedWorkbook = new XSSFWorkbook();
loadVendorsIntoFile(nonManagedWorkbook,vendors,false);
OutputStream outNonManaged = new FileOutputStream("C:\\Users\\User\\unmanaged_out.xlsx");
managedWorkbook.write(outNonManaged);
outNonManaged.close();
This also writes managedWorkbook into C:\\Users\\User\\unmanaged_out.xlsx !
I suspect that you meant that last bit to instead be something like:
OutputStream outNonManaged = new FileOutputStream("C:\\Users\\User\\unmanaged_out2.xlsx");
nonManagedWorkbook.write(outNonManaged);
outNonManaged.close();
Note how the changed snippet both writes into a different file, and importantly, writes out the second workbook you created, rather than outputting the first one twice!

Related

Apache poi: How to setting 'Print on Both Sides' and 'Print one Sided'?

I have a problem when clone new sheet.
Sheet 1 setting 'Print on Both Sides' but after workbook.cloneSheet(0), new sheet lost setting 'Print on Both Sides' and belong to 'Print one Sided'. I can't set 'Print on Both Size' for new sheet because don't find method to set this.
Do poi-apache printSetup() have support setting 'Print on Both Sides' and 'Print one Sided'?
If haven't how to setting this?
Whether a printer is able duplex printing depends on the printer hardware. So this is not a print setup like PrintSetup but a printer setup. Excel is able storing printer setups in it's files. This is done in a binary DEVMODEA structure (Where is the definition of the XLSX printerSettings.bin file format?). In Office Open XML it is stored in /xl/printerSettings/printerSettings[N].bin.
Apache POI is not able cloning that structure properly until now. And I doubt it should be cloned at all because it often leads to problems when Excel files are opened by users which do not have exactly the printer as the creator had. But of course, this is only my opinion and at least for Office Open XML it can be done.
Workbook.cloneSheet does not even clone the PrintSetup until now (current version apache poi 4.1.2). So we need at first cloning the PrintSetup. The following code provides a method for cloning the PrintSetup from Sheet source to Sheet clone. It uses java.beans.* and java.lang.reflect.Method to get all values using getters from sourcePrintSetup and set those values to clonePrintSetup using the appropriate setters. It works only for getters without parameters and setters having exact one parameter. But this will be sufficient for PrintSetup.
Having the PrintSetup cloned, we can correct the cloned references from XSSFSheet to /xl/printerSettings/printerSettings[N].bin. Workbook.cloneSheet simply copies the relation to the old /xl/printerSettings/printerSettings[N].bin package part. This is wrong. The /xl/printerSettings/printerSettings[N].bin package part also needs to be cloned and the the cloned sheet needs to reference that new /xl/printerSettings/printerSettings[N].bin package part . This is done by method repairCloningPrinterSettings in following code. This works using current apache poi 4.1.2. It must be changed when Workbook.cloneSheet changes in later versions.
The following code also provides a method for binary cloning a PackagePart. It works only for part names which ends with Idx followed by dot followed by extension, for example name1.xml or name1.png or printerSettings1.bin. It counts up the Idx while cloning.
Complete Example:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ooxml.*;
import org.apache.poi.openxml4j.opc.*;
import java.io.*;
import java.beans.*;
import java.lang.reflect.Method;
class ExcelCloneSheet {
//method to transfer InputStream to OutputStream
//to work using Java 8 since InputStream.transferTo needs at least Java 9
static void transferInputStreamToOutputStream(InputStream in, OutputStream out) throws Exception {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
//method for binary cloning a PackagePart
//works only for part names which ends with Idx followed by dot followed by extension
//throws Exception when not successful
static PackagePart clonePackagePart(PackagePart sourcePart, String contentType) throws Exception {
OPCPackage oPCPackage = sourcePart.getPackage();
String sourcePartName = sourcePart.getPartName().getName();
String destinationPartName = sourcePartName;
String[] sourcePartNameSplitExtension = sourcePartName.split("\\.");
if (sourcePartNameSplitExtension.length == 2) {
sourcePartName = sourcePartNameSplitExtension[0];
String sourcePartNameExtension = sourcePartNameSplitExtension[1];
int i = sourcePartName.length();
while (i > 0 && Character.isDigit(sourcePartName.charAt(i - 1))) {
i--;
}
int idx = Integer.valueOf(sourcePartName.substring(i));
idx++;
destinationPartName = sourcePartName.substring(0, i) + idx + "." + sourcePartNameExtension;
}
PackagePartName partName = PackagingURIHelper.createPartName(destinationPartName);
PackagePart destinationPart = oPCPackage.createPart(partName, contentType);
InputStream in = sourcePart.getInputStream();
OutputStream out = destinationPart.getOutputStream();
//in.transferTo(out); // at least Java 9 needed
transferInputStreamToOutputStream(in, out);
out.close();
return destinationPart;
}
//method for repairing the relation from sheet to "/xl/printerSettings/printerSettings[N].bin" package part
//clones "/xl/printerSettings/printerSettings[N].bin" package part
//repairs the wrong cloned relation to the old "/xl/printerSettings/printerSettings[N].bin" package part
//works using apache poi 4.1.2
//must be changed when Workbook.cloneSheet changes in later versions
static void repairCloningPrinterSettings(XSSFSheet sheet) throws Exception {
for (POIXMLDocumentPart.RelationPart relationPart : sheet.getRelationParts()) {
String contentType = relationPart.getDocumentPart().getPackagePart().getContentType();
if ("application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings".equals(contentType)) {
System.out.println(relationPart.getRelationship());
//clone the "/xl/printerSettings/printerSettings[N].bin" package part
PackagePart sourcePart = relationPart.getDocumentPart().getPackagePart();
PackagePart destinationPart = clonePackagePart(sourcePart, contentType);
//remove the wrong cloned relation to the old "/xl/printerSettings/printerSettings[N].bin" package part
relationPart.getRelationship().getSource().removeRelationship(relationPart.getRelationship().getId());
//add the relation to the new "/xl/printerSettings/printerSettings[N].bin" package part
PackageRelationship relationship = sheet.getPackagePart().addRelationship(
destinationPart.getPartName(),
TargetMode.INTERNAL,
XSSFRelation.PRINTER_SETTINGS.getRelation());
//set Id of relation to the new "/xl/printerSettings/printerSettings[N].bin" package part
//in sheet's page setup
if (sheet.getCTWorksheet().getPageSetup() == null) sheet.getCTWorksheet().addNewPageSetup();
sheet.getCTWorksheet().getPageSetup().setId(relationship.getId());
}
}
}
//method for cloning the PrintSetup from Sheet source to Sheet clone
//uses java.beans.* and java.lang.reflect.Method to get all values using getters from sourcePrintSetup
//and set those values to clonePrintSetup using the appropriate setters
//works only for getters without parameters and setters having exact one parameter
//throws Exception when not successful
static void clonePrintSetup(Sheet source, Sheet clone) throws Exception {
PrintSetup sourcePrintSetup = source.getPrintSetup();
PrintSetup clonePrintSetup = clone.getPrintSetup();
for(PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo(PrintSetup.class).getPropertyDescriptors()) {
Method getMethod = propertyDescriptor.getReadMethod();
Object value = null;
if (getMethod != null && getMethod.getParameterTypes().length == 0) {
value = getMethod.invoke(sourcePrintSetup);
Method setMethod = propertyDescriptor.getWriteMethod();
if (setMethod != null && setMethod.getParameterTypes().length == 1) {
setMethod.invoke(clonePrintSetup, value);
System.out.println(setMethod + ": " + value);
}
}
}
}
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("Excel.xlsx"));
Sheet sheet = workbook.getSheetAt(0);
Sheet clone = workbook.cloneSheet(0);
//Workbook.cloneSheet does not clone the PrintSetup. So we do it now.
clonePrintSetup(sheet, clone);
if (clone instanceof XSSFSheet) {
XSSFSheet xssfSheet = (XSSFSheet)clone;
//After cloning the cloned sheet has relation to the same
//"/xl/printerSettings/printerSettings[N].bin" package part as the source sheet had.
//This is wrong. So we need to repair.
repairCloningPrinterSettings(xssfSheet);
}
FileOutputStream out = new FileOutputStream("ExcelNew.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
After that code the cloned sheet in ExcelNew.xlsx should have same PrintSetup and also printerSettings as the source sheet.

Copy all kind of RELATIONS from one workbook to new workbook Apache POI XSSFWorkbook

I have been trying to take relations from one workbook and copying them over to another newly created workbook.
So far I have tried this:
XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\pivottablesurvey.xlsx")); //src workbook
XSSFWorkbook newWB = new XSSFWorkbook(); //target workbook
POIXMLDocument upcastOldwb = oldWB; //Upcasting
POIXMLDocument upcastNewwb = newWB; //Upcasting
for (PackageRelationship pr : upcastOldwb.getPackagePart().getRelationships()) {
upcastNewwb.getPackagePart().getRelatedPart(pr).addRelationship(pr.getTargetURI(),pr.getTargetMode(), pr.getRelationshipType());
}
At this point, I get this error:
Exception in thread "main" java.lang.IllegalArgumentException: Relationship id=rId1 - container=org.apache.poi.openxml4j.opc.ZipPackage#5ffdc730 - relationshipType=http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet - source=/xl/workbook.xml - target=/xl/worksheets/sheet1.xml,targetMode=INTERNAL doesn't start with this part /xl/workbook.xml
First of all, I will admit that I don't even know if the approach that I have taken is correct. I am just trying to copy relations from one workbook to another workbook.
Any help will be appreciated.
Thanks
Edit 2
Is this what you are referring to when you say that that part has to exist first?
XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\pivottablesurvey.xlsx")); //src workbook
XSSFWorkbook newWB = new XSSFWorkbook(); //target workbook
POIXMLDocument upcastOldwb = oldWB; //Upcasting
POIXMLDocument upcastNewwb = newWB; //Upcasting
//Different code from above (the actual question). Is this what you thought I missed?
for (PackageRelationship pr : upcastOldwb.getPackagePart().getRelationships()) {
URI target = pr.getTargetURI();
if(target.getFragment() != null) {
String t = target.toString();
try {
target = new URI( t.substring(0, t.indexOf('#')) );
} catch(URISyntaxException e) {
throw new InvalidFormatException("Invalid target URI: " + target);
}
}
PackagePartName relName = PackagingURIHelper.createPartName(target);
upcastNewwb.getPackagePart().getPackage().createPart(relName, upcastOldwb.getPackagePart().getContentType());
}
Edit 1:
My ultimate goal is to copy sheet(s) from one workbook to another. There are other suggestions/solutions. I even implemented one by myself without looking at other solutions.
I implemented the suggestion given here by Gagravarr. As it turned out, my implementation is 99 % the same as other solutions found here on SO and coderanch. But there is a problem with that solution. If the sheets contains tables, pictures, graphs, etc, then those solutions don't work well.
Then I thought of a clever way to copy sheets to new workbook: By process of Elimination! This solution is the best out of the rest. It keeps everything intact and no graph, chart, picture would break. But as you can tell, that is a hacky way. Not the cool way. So I want to implement something that is a proper way. Or a professional developer way.
So to do this, I looked into XSSFWorkbook.cloneSheet(...) method and how it is implemented by developers at Apache. I am trying to replicate it. So far in my attempt, every thing is going according to the plan, with one little problem. And that problem is the original question above. Let me show you my code first:
public static void main(String[] args) throws Exception {
XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\faraz\\Documents\\pivottablesurvey.xlsx"));
XSSFWorkbook newWB = new XSSFWorkbook();
for (int i = 0; i < oldWB.getNumberOfSheets(); i++) {
XSSFSheet sheetFromOldWB = (XSSFSheet) oldWB.getSheetAt(i);
XSSFSheet sheetForNewWB = (XSSFSheet) newWB.createSheet(sheetFromOldWB.getSheetName());
/*
* Behold! Below this point, I am trying to mimic XSSFWorkbook.cloneSheet(...) method
*/
List<RelationPart> rels = sheetFromOldWB.getRelationParts();
XSSFDrawing dg = null;
for(RelationPart rp : rels) {
POIXMLDocumentPart r = rp.getDocumentPart();
if(r instanceof XSSFDrawing) {
dg = (XSSFDrawing)r;
continue;
}
addRelation(rp, sheetForNewWB); //This is a private method in XSSFWorkbook class so I copied this method over to this class
}
try {
for(PackageRelationship pr : sheetFromOldWB.getPackagePart().getRelationships()) {
if (pr.getTargetMode() == TargetMode.EXTERNAL) {
sheetForNewWB.getPackagePart().addExternalRelationship
(pr.getTargetURI().toASCIIString(), pr.getRelationshipType(), pr.getId());
}
}
} catch (InvalidFormatException e) {
throw new POIXMLException("Failed to clone sheet", e);
}
OutputStream out = new ByteArrayOutputStream();
Method writeReflect = sheetFromOldWB.getClass().
getDeclaredMethod("write", OutputStream.class); //I had to use reflection here to get it to work because write(OutputStream os) is a private method in XSSFWorkbook class
writeReflect.setAccessible(true);
Object w = writeReflect.invoke(sheetFromOldWB,out);
Method readReflect = sheetFromOldWB.getClass().
getDeclaredMethod("read", InputStream.class); //Same reason as above
readReflect.setAccessible(true);
Object r = readReflect.invoke(sheetForNewWB,new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray()));
CTWorksheet ct = sheetForNewWB.getCTWorksheet();
if(ct.isSetLegacyDrawing()) {
System.out.println("Cloning sheets with comments is not yet supported.");
ct.unsetLegacyDrawing();
}
if (ct.isSetPageSetup()) {
System.out.println("Cloning sheets with page setup is not yet supported.");
ct.unsetPageSetup();
}
sheetForNewWB.setSelected(false);
if (dg != null) {
if(ct.isSetDrawing()) {
ct.unsetDrawing();
}
XSSFDrawing clonedDg = sheetForNewWB.createDrawingPatriarch();
clonedDg.getCTDrawing().set(dg.getCTDrawing());
clonedDg = sheetForNewWB.createDrawingPatriarch();
List<RelationPart> srcRels = sheetFromOldWB.createDrawingPatriarch().getRelationParts();
for (RelationPart rp : srcRels) {
addRelation(rp, clonedDg);
}
}
}
FileOutputStream fileOut = new FileOutputStream("F:\\faraz\\Documents\\output.xlsx");
newWB.write(fileOut);
oldWB.close();
newWB.close();
fileOut.close();
}
private static void addRelation(RelationPart rp, POIXMLDocumentPart target) {
PackageRelationship rel = rp.getRelationship();
if (rel.getTargetMode() == TargetMode.EXTERNAL) {
target.getPackagePart().addRelationship(
rel.getTargetURI(), rel.getTargetMode(), rel.getRelationshipType(), rel.getId());
} else {
XSSFRelation xssfRel = XSSFRelation.getInstance(rel.getRelationshipType());
if (xssfRel == null) {
throw new POIXMLException("Can't clone sheet - unknown relation type found: "+rel.getRelationshipType());
}
**target.addRelation(rel.getId(), xssfRel, rp.getDocumentPart());**
}
}
That line with double astericks target.addRelation(rel.getId(), xssfRel, rp.getDocumentPart()); is giving me a trouble. When I run this program as is, I get this error:
Exception in thread "main" java.lang.IllegalArgumentException: No part found for relationship id=rId1 - container=org.apache.poi.openxml4j.opc.ZipPackage#50c91c07 - relationshipType=http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable - source=/xl/worksheets/sheet1.xml - target=/xl/pivotTables/pivotTable1.xml,targetMode=INTERNAL
at org.apache.poi.openxml4j.opc.PackagePart.getRelatedPart(PackagePart.java:487)
at org.apache.poi.POIXMLDocumentPart.findExistingRelation(POIXMLDocumentPart.java:378)
at org.apache.poi.POIXMLDocumentPart.addRelation(POIXMLDocumentPart.java:343)
at oldmain.addRelation(oldmain.java:112)
at oldmain.main(oldmain.java:50)
It is looking for relations at this point! Actually, I should say I believe its looking for relation inside the workbook because I am not sure. But it cannot find them there because I am not cloning the sheets within the same workbook.
And this is my actual question here. What is it looking for here? Is what I think is correct? Is it actually looking for some relations inside the workbook? If my thinking is correct, then I need to copy all relations from source workbook to new workbook.
One thing, if I just comment out that line, then the method works okay. It would copy over everything but the graphs or pictures don't look good. I mean, it would copy over the Integers and Strings, etc but the graphs, pictures and charts would be missing. Let me show you what I meant:
Source Sheet:
Result Sheet:
Source Sheet:
Result Sheet:
You see that, it is working somewhat but not fully. And I believe that's because it's missing some kind of relations. Now, why I came to that realization is because I dug inside that line to see what is it calling and what does it want.
So, is it possible to copy all the relations from one workbook to another? Is it actually what I need for this code to work?
Thanks again and I shall really appreciate any help.

How to properly wire together readers and writers for PostgreSQL COPY?

I'm trying to use PostgreSQL COPY command to import data without creating temporary files. Initial data is in a format that requires conversion so I have something like this:
void itemsToCsv(String filename, Writer writer) {
/* Start processing */
CSVPrinter printer = new CSVPrinter(writer, CSVFormat.DEFAULT)
for(Array[String] row: processedFile) {
printer.printRecord(row);
}
}
Now here comes the problem. I was thinking about using something like this code
CopyManager copyMgr = (BaseConnection) conn.getCopyAPI();
Writer w = new PipedWriter();
Reader r = new PipedReader(w);
CopyIn cpin = copyMgr.copyIn("COPY items_import (id, name)FROM STDIN CSV", r);
itemsToCsv("items_in_weird_format.xml", w)
As far as I understand, the copyIn method will block, because there's nothing to read yet. Is there some clever way to wire readers and writers together without resorting to CopyIn.writeToCopy method?
UPD. Solved by wrapping call to itemsToCsv in a thread.

Java: CSV File Easy Read/Write

I'm working on a program that requires quick access to a CSV comma-delimited spreadsheet file.
So far I've been able to read from it easily using a BufferedReader.
However, now I want to be able to edit the data it reads, then export it BACK to the CSV.
The spreadsheet contains names, phone numbers, email addresses, etc. And the program lists everyone's data, and when you click on them it brings up a page with more detailed information, also pulled from the CSV. On that page you can edit the data, and I want to be able to click a "Save Changes" button, then export the data back to its appropriate line in the CSV--or delete the old one, and append the new.
I'm not very familiar with using a BufferedWriter, or whatever it is I should be using.
What I started to do is create a custom class called FileIO. It contains both a BufferedReader and a BufferedWriter. So far it has a method that returns bufferedReader.readLine(), called read(). Now I want a function called write(String line).
public static class FileIO {
BufferedReader read;
BufferedWriter write;
public FileIO (String file) throws MalformedURLException, IOException {
read = new BufferedReader(new InputStreamReader (getUrl(file).openStream()));
write = new BufferedWriter (new FileWriter (file));
}
public static URL getUrl (String file) throws IOException {
return //new URL (fileServer + file).openStream()));
FileIO.class.getResource(file);
}
public String read () throws IOException {
return read.readLine();
}
public void write (String line) {
String [] data = line.split("\\|");
String firstName = data[0];
// int lineNum = findLineThatStartsWith(firstName);
// write.writeLine(lineNum, line);
}
};
I'm hoping somebody has an idea as to how I can do this?
Rather than reinventing the wheel you could have a look at OpenCSV which supports reading and writing of CSV files. Here are examples of reading & writing
Please consider Apache commons csv.
To fast understand the api, there are four important classes:
CSVFormat
Specifies the format of a CSV file and parses input.
CSVParser
Parses CSV files according to the specified format.
CSVPrinter
Prints values in a CSV format.
CSVRecord
A CSV record parsed from a CSV file.
Code Example:
Unit test code:
The spreadsheet contains names, phone numbers, email addresses, etc. And the program lists everyone's data, and when you click on them it brings up a page with more detailed information, also pulled from the CSV. On that page you can edit the data, and I want to be able to click a "Save Changes" button, then export the data back to its appropriate line in the CSV--or delete the old one, and append the new.
The content of a file is a sequence of bytes. CSV is a text based file format, i.e. the sequence of byte is interpreted as a sequence of characters, where newlines are delimited by special newline characters.
Consequently, if the length of a line increases, the characters of all following lines need to be moved to make room for the new characters. Likewise, to delete a line you must move the later characters to fill the gap. That is, you can not update a line in a csv (at least not when changing its length) without rewriting all following lines in the file. For simplicity, I'd rewrite the entire file.
Since you already have code to write and read the CSV file, adapting it should be straightforward. But before you do that, it might be worth asking yourself if you're using the right tool for the job. If the goal is to keep a list of records, and edit individual records in a form, programs such as Microsoft Access or whatever the Open Office equivalent is called might be a more natural fit. If you UI needs go beyond what these programs provide, using a relational database to keep your data is probably a better fit (more efficient and flexible than a CSV).
Add Dependencies
implementation 'com.opencsv:opencsv:4.6'
Add Below Code in onCreate()
InputStreamReader is = null;
try {
String path= "storage/emulated/0/Android/media/in.bioenabletech.imageProcessing/MLkit/countries_image_crop.csv";
CSVReader reader = new CSVReader(new FileReader(path));
String[] nextLine;
int lineNumber = 0;
while ((nextLine = reader.readNext()) != null) {
lineNumber++;
//print CSV file according to your column 1 means first column, 2 means
second column
Log.e(TAG, "onCreate: "+nextLine[2] );
}
}
catch (Exception e)
{
Log.e(TAG, "onCreate: "+e );
}
I solved it using
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.8.6</version>
</dependency>
and
private static final CsvMapper mapper = new CsvMapper();
public static <T> List<T> readCsvFile(MultipartFile file, Class<T> clazz) throws IOException {
InputStream inputStream = file.getInputStream();
CsvSchema schema = mapper.schemaFor(clazz).withHeader().withColumnReordering(true);
ObjectReader reader = mapper.readerFor(clazz).with(schema);
return reader.<T>readValues(inputStream).readAll();
}

Writing multiple files with Spring Batch

I'm a newbie in Spring Batch, and I would appreciate some help to resolve this situation: I read some files with a MultiResourceItemReader, make some marshalling work, in the ItemProcessor I receive a String and return a Map<String, List<String>>, so my problem is that in the ItemWriter I should iterate the keys of the Map and for each one of them generate a new file containing the value associated with that key, can someone point me out in the right direction in order to create the files?
I'm also using a MultiResourceItemWriter because I need to generates files with a maximum of lines.
Thanks in advance
Well, finaly got a solution, I'm not really excited about it but it's working and I don't have much more time, so I've extended the MultiResourceItemWriter and redefined the "write" method, processing the map's elements and writing the files by myself.
In case anyone out there needs it, here it is.
#Override
public void write(List items) throws Exception {
for (Object o : items) {
//do some processing here
writeFile(anotherObject);
}
private void writeFile (AnotherObject anotherObject) throws IOException {
File file = new File("name.xml");
boolean restarted = file.exists();
FileUtils.setUpOutputFile(file, restarted, true, true);
StringBuffer sb = new StringBuffer();
sb.append(xStream.toXML(anotherObject));
FileOutputStream os = new FileOutputStream(file, true);
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(os, Charset.forName("UTF-8")));
bufferedWriter.write(sb.toString());
bufferedWriter.close();
}
And that's it, I want to believe that there is a better option that I don't know, but for the moment this is my solution. If anyone knows how can I enhance my implementation, I'd like to know it.

Categories

Resources