Writing array of objects to a file with Gson - java

public boolean wirteJson(Passenger passenger[]){
try {
file = new FileWriter(System.getProperty("user.dir")+"/"+fileName);
for (int i = 0; i < 10; i++) {
String json =gson.toJson(passenger[i]);
file.write(json);
}
file.flush();
file.close();
} catch (IOException ex) {
return false;
}
return false;
}
I'm trying to write the passenger array to a file with Gson. I'm open to alternatives.

You don't have to serialize the given input array by each element:
Gson can do it all itself;
your method assumes the input array is exactly 10 elements long (thus, throwing ArrayIndexOutOfBoundsException if the input array has less elements, or writing only first 10 elements);
your method does not write well-formed JSON: {},{},{} is invalid, whilst [{},{},{}] is;
your method, as suggested by RealSkeptic, does not need intermediate string representations.
All you need are just two methods Gson.toJson and Gson.fromJson.
So, here is a simple example:
final class Passenger {
final String name;
Passenger(final String name) {
this.name = name;
}
}
public static void main(final String... args)
throws IOException {
final File file = createTempFile("q43439637_", "_q43439637");
file.deleteOnExit();
try ( final FileWriter fileWriter = new FileWriter(file) ) {
final Passenger[] before = { new Passenger("Alice"), new Passenger("Bob") };
gson.toJson(before, fileWriter);
}
try ( final FileReader fileReader = new FileReader(file) ) {
final Passenger[] after = gson.fromJson(fileReader, Passenger[].class);
for ( final Passenger p : after ) {
System.out.println(p.name);
}
}
}
Output:
Alice
Bob
P.S. Your out-of-catch return seems to have to return true rather than false. Also, flush() is unnecessary before close().

Related

How to read from a file and then analyze this data?

I am a begginer(recently began learning) at programming in Java and I need help.
I have to read from a file, which contains numbers. I would like to make a method for reading from a file. Then I need to analyze this data and write it in another file.
What I strugle with is if I make a method just to read from a file or do I also have to save this read data into a variable. Where should this variable be declared inside a method (if is inside, how do I use it outside), if is outside how do I use it inside a method and also outside. Can anyone help me clarify this? What am I doing wrong?
My code of what I wrote until now. File from which I had to read has houndreds of numbers.
public class Test1 {
public static void main(String[] args) {
String nameFile = "numbers.txt";
File file = new File(nameFile);
String contentFile ="";
}
//Method for reading a .txt file
private static String readFromFile(String nameFile, String contentFile) {
String line = "";
try {
BufferedReader read = new BufferedReader(new FileReader(nameFile));
while((line = read.readLine()) != null) {
line = contentFIle;
}
read.close();
} catch (IOException e) {
System.out.println("There was an error reading from a file");
}
return line;
}
}
Theoretically speaking: mathematical functions get input variables, they preform some transformation on the variables and output the result of the transformation.
For example: f(x) = x - 1, g(x) = x * 2
You can chain functions in a way that one functions output will be the other function input: g(f(2)). In this case, the number 2 is used as an input for function f(x) and the output of f(x) is the input of g(x).
Functions and methods in programming can work in a similar way, but It may be more readable to save function output into meaningful variable names, and then to apply these variables to the next function.
Instead of doing: outputText(processText(readText(someFilename)))
You can write (pseudocode):
someFilename = 'foo'
text = readText(someFilename)
processed = processText(text)
outputText(processed)
In java and in your context this would look like the following:
public class Test1 {
public static void main(String[] args) {
String nameFile = "numbers.txt";
String contentFile = readFromFileByName(nameFile);
String altered = processText(contentFile);
saveToFile(altered, "processed.txt");
}
private static String readFromFileByName(String nameFile) {
String fullRead = "";
try {
File file = new File(nameFile);
BufferedReader read = new BufferedReader(new FileReader(file));
String line; // define line variable
while((line = read.readLine()) != null) {
fullRead += line; // pay attention for the altered code
}
read.close();
} catch (IOException e) {
System.out.println("There was an error reading from a file");
} finally {
return fullRead;
}
}
private static List<Integer> stringToIntList(String string) {
return Arrays
.stream(text.split(", "))
.map(Integer::parseInt)
.collect(Collectors.toList());
}
private static String processText(String text) {
String processed = text.replace('H', 'h'); // Some heavy processing :)
return processed;
}
private static void saveToFile(String text, String fileName) {
// save <text> to file with filename <filename>
}
}
1) Line is the variable that you have read to. So you shouldn't change its value.
line = contentFIle;
if you need only first line this method should look like:
private static String readFromFile(String nameFile) {
String line = "";
try {
BufferedReader read = new BufferedReader(new FileReader(nameFile));
line = read.readLine();
read.close();
} catch (IOException e) {
System.out.println("There was an error reading from a file");
}
return line;
}
if you need a list of this:
List<String> lines = Collections.emptyList();
try {
Files.readAllLines(Paths.get(fileName), StandardCharsets.UTF_8);
} catch (IOException e) {
// do something
e.printStackTrace();
}
return lines;
2) Also you don't call readFromFile function. So you need to change the main method:
public static void main(String[] args) {
String nameFile = "numbers.txt";
String contentFile = readFromFile(nameFile);
}
3)For your particular case, there's no sense to call readFromFile with String contentFile because you don't use this variable.

How to write to file a sorted array java

How to write a constructor that holds the sorted array, Then write it to a file with a method like getDatabase that returns an object that has been passed the sorted array.
Database class:
public Person[] entry; // this needs to be an array that will hold the person obj each new entry to the array is added to the next avail pos in list
public Database(int capacity) {
entry = new Person[capacity];
size = 0;
}
public Person[] getDatabase() {
return entry;
}
Storage Class:
public dataBase writeCommaSeparated(Database data) throws IOException {
Database db = new Database();
PrintStream writer = new PrintStream(file);
if(file.exists()) {
for(int i = 0; i < data.size; i++) {
writer.println(data.get(i).toFile());
}
}
writer.close();
return db;
}
public dataBase read() throws IOException {
Database db = new Database();
Scanner scan = new Scanner(file);
Person person;
//check if file has data print selected data
while(scan.hasNextLine()) {
person = parsePerson(scan.nextLine());
db.add(person);
}
scan.close();
return db;
}
These are just snippets of the code that I have. I am trying to write a sorted array into a file, and I know that it is sorting the file by age correctly but I am not sure how to write it out to a file.
in main I have:
String fileLocation = File.separator + "Users"
+ File.separator + "USERNAME"
+ File.separator + "Desktop"
+ File.separator + "DataFile.txt";
FileStorage fileStore = new FileStorage(fileLocation);
FileData data = fileStore.read(); // this invokes a method called read that reads the file
data.sort(); // sorts the file by age and prints out to the console the sorted age
fileSort.writeCommaSeparated(data); // writes to the file in a commaseparated way
Focusing on just the sorting of a csv file based on age and given your description, this was about the simplest solution that came to mind.
public class PersonDatabase {
private ArrayList<String[]> people = new ArrayList();
// Reads the given input file and loads it into an ArrayList of string arrays.
public PersonDatabase(String inputFile) throws IOException {
BufferedReader in = new BufferedReader(new FileReader(inputFile));
for (String line = null; null != (line=in.readLine()); ) {
people.add(line.split(",")); // convert csv string to an array of strings.
}
in.close();
}
private static final int AGE_COLUMN_INDEX=2; // Identifies the 'age' column
// performs a numeric comparison on the 'age' column values.
int compareAge(String[] a1, String[]a2) {
return Integer.compare(
Integer.parseInt(a1[AGE_COLUMN_INDEX]),
Integer.parseInt(a2[AGE_COLUMN_INDEX]));
}
// Sorts the list of people by age and writes to the given output file.
public void writeSorted(String outputFile) throws IOException {
PrintWriter out = new PrintWriter(new FileWriter(outputFile));
people.stream()
.sorted(this::compareAge) // sort by age
.forEach(a->{
Arrays.stream(a).forEach(s->out.print(s+",")); // print as csv
out.println();
});
out.close();
}
public static void main(String[] args) throws IOException {
PersonDatabase pdb = new PersonDatabase("persondb.in");
pdb.writeSorted("persondb.out");
}
}
Given the following input:
fred,flintstone,43,
barney,rubble,42,
wilma,flintstone,39,
betty,rubble,39,
This program produces the following output:
wilma,flintstone,39,
betty,rubble,39,
barney,rubble,42,
fred,flintstone,43,
It seemed like marshalling these arrays into Person objects just for the sake of sorting was overkill. However, if you wanted to do that, it would be pretty easy to turn an array of field values into a Person object. I'll leave that to you.

Gson: How to skip rows in JSON array while parsing using stream api

Am trying to parse a huge JSON array using Gson stream where for every run, I just have to process 10 objects at a time.
So that on first run, it process 10. In second run, it starts from 11th. In third, it starts from 21st and so on... You get the drill.
JSON array is in the format:
[
{ "key1": "value1"},
{ "key2": "value2"},
{ "key3": "value3"},
{ "key4": "value4"},
..........
.........
..........
{ "key10": "value10"},
..........
.........
..........
{ "key20": "value20"},
..........
.........
..........
]
Am trying below code but seems like it doesn't work properly and am parsing always from the start only. This is what am doing:
public static void readJsonStream(int skipRows) {
JsonReader reader = null;
String FILENAME = "/examples/uh_data.json";
final InputStream stream = UHReportParser.class.getClass().getResourceAsStream(FILENAME);
try {
reader = new JsonReader(new InputStreamReader(stream, "UTF-8"));
Gson gson = new GsonBuilder().create();
// Read file in stream mode
reader.beginArray();
int count = 1;
while (reader.hasNext()) {
if (count++<=skipRows){
continue;
} else if(count>skipRows+10){
break;
}
else{
UserData data = null;
// Read data into object model
data = gson.fromJson(reader, UserData.class); //starts from one again
String description = data.getDescription();
}
}
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
} catch (IOException ex) {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
What should be modified here? How can I achieve the desired results?
I didn't analyze your algorithm in depth, but it doesn't seem to skip values at the "skip" phase and I would definitely refactor your JSON stream reader in order to make it as clean as possible (at least for what I can do).
This would allow you to reuse such a method as much as possible too.
Consider the following methods:
static void readArrayBySkipAndLimitFromBegin(final JsonReader jsonReader, final int skip, final int limit,
final Consumer<? super JsonReader> callback)
throws IOException {
readArrayBySkipAndLimit(jsonReader, skip, limit, true, false, callback);
}
static void readArrayBySkipAndLimit(final JsonReader jsonReader, final int skip, final int limit, final boolean processBegin,
final boolean processEnd, final Consumer<? super JsonReader> callback)
throws IOException {
// the JSON stream can be already processed somehow
if ( processBegin ) {
jsonReader.beginArray();
}
// just skip the `skip`
for ( int i = 0; i < skip && jsonReader.hasNext(); i++ ) {
jsonReader.skipValue();
}
// and limit to the `limit` just passing the JsonReader instance to its consumer elsewhere
for ( int i = 0; i < limit && jsonReader.hasNext(); i++ ) {
callback.accept(jsonReader);
}
// in case you need it ever...
if ( processEnd ) {
while ( jsonReader.hasNext() ) {
jsonReader.skipValue();
}
jsonReader.endArray();
}
}
Here is a JSON document I was using to test it (32 array elements in total):
[
{"key1": "value1"},
{"key2": "value2"},
...
{"key31": "value31"},
{"key32": "value32"}
]
Now, test it:
private static final Gson gson = new Gson();
private static final Type mapOfStringToStringType = new TypeToken<Map<String, String>>() {}.getType();
public static void main(final String... args)
throws IOException {
// read up to 2B+ entries, every 10 rows
for ( int i = 0; i >= 0; i += 10 ) {
System.out.print("Step #" + i / 10 + ": ");
final Collection<Map<String, String>> maps = new ArrayList<>();
// consume and close
try ( final JsonReader jsonReader = Resources.getPackageResourceJsonReader(Q50737654.class, "array.json") ) {
// consume the JSON reader, parse each array page element and add it to the result collection
readArrayBySkipAndLimitFromBegin(jsonReader, i, 10, jr -> maps.add(gson.fromJson(jr, mapOfStringToStringType)));
}
System.out.println(maps);
if ( maps.isEmpty() ) {
break;
}
}
System.out.println("Done");
}
Example output:
Step #0: [{key1=value1}, {key2=value2}, {key3=value3}, {key4=value4}, {key5=value5}, {key6=value6}, {key7=value7}, {key8=value8}, {key9=value9}, {key10=value10}]
Step #1: [{key11=value11}, {key12=value12}, {key13=value13}, {key14=value14}, {key15=value15}, {key16=value16}, {key17=value17}, {key18=value18}, {key19=value19}, {key20=value20}]
Step #2: [{key21=value21}, {key22=value22}, {key23=value23}, {key24=value24}, {key25=value25}, {key26=value26}, {key27=value27}, {key28=value28}, {key29=value29}, {key30=value30}]
Step #3: [{key31=value31}, {key32=value32}]
Step #4: []
Done
As you can see, it's really easy.

Writing to a instance variables to a text file

I need to take a list of Objects and write their instance variables to a text file. It would look something like this:
Hot Dog,1.25,Grocery Store
Gas,42.15,Gas Station
etc.
I have some code that looks like this:
public void writeListToFile(String fileName, ArrayList<BudgetItem> writeList) throws Exception {
PrintWriter out = null;
for(int i = 0; i<writeList.size(); i++) {
if(writeList.get(i) instanceof Expense) {
Expense writeExpense = (Expense) writeList.get(i);
try {
out = new PrintWriter(new FileWriter(fileName));
dump(out, writeExpense);
}
finally {
}
}
else if(writeList.get(i) instanceof Income) {
Income writeIncome = (Income) writeList.get(i);
try {
out = new PrintWriter(new FileWriter(fileName));
dump(out, writeIncome);
}
finally {
}
}
}
out.close();
}
public void dump(PrintWriter out, Expense writeExpense) {
out.print(writeExpense.getDateOfTransaction().get(GregorianCalendar.YEAR));
out.print(",");
out.print(writeExpense.getDateOfTransaction().get(GregorianCalendar.MONTH));
out.print(",");
out.print(writeExpense.getDateOfTransaction().get(GregorianCalendar.DATE));
out.print(",");
out.print(writeExpense.getItemName());
out.print(",");
out.print(writeExpense.getMethodOfPay());
out.print(",");
out.print(writeExpense.getPlaceOfPurchase());
out.print(",");
out.print(writeExpense.getQuantity());
out.print(",");
out.print(writeExpense.getPrice());
out.print("\n");
}
and one other method similar to the 2nd one.
When I run it, it only writes out one line, the first object in the list, and nothing else. I can't figure out what's going on. I know object serialization is a faster option, but for this project, since I am still learning, I want to use this way.
Main method as requested by one of the answers:
public static void main(String[] args) throws Exception {
String itemName = "Hot Dog";
int quantity = 1;
String placeOfPurchase = "Weiner Stand";
String methodOfPay = "Credit";
BigDecimal price = new BigDecimal(1.25);
GregorianCalendar g = new GregorianCalendar(2013,11,1);
Expense e = new Expense(g, price, itemName, quantity, placeOfPurchase, methodOfPay);
BudgetItem bi = (BudgetItem) e;
String itemName2 = "Gun";
int quantity2 = 1;
String placeOfPurchase2 = "Weiner Stand";
String methodOfPay2 = "Credit";
BigDecimal price2 = new BigDecimal(1.25);
GregorianCalendar g2 = new GregorianCalendar(2013,11,1);
Expense e2 = new Expense(g, price, itemName, quantity, placeOfPurchase, methodOfPay);
BudgetItem bi2 = (BudgetItem) e2;
ArrayList<BudgetItem> abi = new ArrayList<BudgetItem>();
abi.add(bi);
abi.add(bi2);
RegisterFileIO rfio = new RegisterFileIO();
rfio.writeListToFile(System.getProperty("user.dir") + "/data.out", abi);
BufferedReader in = new BufferedReader(new FileReader(System.getProperty("user.dir") + "/data.out"));
Scanner lineScanner = new Scanner(in);
lineScanner.useDelimiter(",");
while(lineScanner.hasNext()) {
System.out.println(lineScanner.next());
}
}
I believe the problem is you creating a new PrintWriter each iteration. You should declare it outside the loop. What is happened is that when a new PrintWriter is created it overwrites the previous data stored in the file.
PrintWriter out = null;
try {
out = new PrintWriter(new FileWriter(fileName));
for(int i = 0; i<writeList.size(); i++) {
if(writeList.get(i) instanceof Expense) {
Expense writeExpense = (Expense) writeList.get(i);
dump(out, writeExpense);
}
} finally {
}
This is because you're instantiating a new PrintWriter object (and a new FileWriter object) for each object in your list.
You should instantiate it only once, before the for loop. Replace
PrintWriter out = null;
with
PrintWriter out = new PrintWriter(new FileWriter(fileName));
Just a side note: with your current code, you might end up with a NullPointerException at line out.close(); if your ArrayList is empty.
First: you are writing java, not C++. Use Java structures and techniques.
As mentioned by MadConan, your implementation is overkill. Use toString() (or toBlammy() - blammy being something other than string) on each object type (Expense and Income) to format the output.
Hint: anytime you have a bunch of if (instanceof blammy) you should consider polymorphism instead.
You code should look something like this:
public void writeListToFile(
final String fileName,
final List<BudgetItem> listBudgetItem)
throws Exception
{
PrintWriter out = null;
try
{
out = new PrintWriter(new FileWriter(fileName));
for(BudgetItem current : listBudgetItem)
{
out.println(current.toBlammy());
}
}
catch (... exceptions)
{
}
finally
{
// close the PrintWriter.
}
}

Array variable initialization error in Java

I am trying to write a Java program that reads an input file consisting of URLs, extracts tokens from these, and keeps track of how many times each token appears in the file. I've written the following code:
import java.io.*;
import java.net.*;
public class Main {
static class Tokens
{
String name;
int count;
}
public static void main(String[] args) {
String url_str,host;
String htokens[];
URL url;
boolean found=false;
Tokens t[];
int i,j,k;
try
{
File f=new File("urlfile.txt");
FileReader fr=new FileReader(f);
BufferedReader br=new BufferedReader(fr);
while((url_str=br.readLine())!=null)
{
url=new URL(url_str);
host=url.getHost();
htokens=host.split("\\.|\\-|\\_|\\~|[0-9]");
for(i=0;i<htokens.length;i++)
{
if(!htokens[i].isEmpty())
{
for(j=0;j<t.length;j++)
{
if(htokens[i].equals(t[j].name))
{ t[j].count++; found=true; }
}
if(!found)
{
k=t.length;
t[k].name=htokens[i];
t[k].count=1;
}
}
}
System.out.println(t.length + "class tokens :");
for(i=0;i<t.length;i++)
{
System.out.println(
"name :"+t[i].name+" frequency :"+t[i].count);
}
}
br.close();
fr.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
But when I run it, it says: variable t not initialized.. What should I do to set it right?
Arrays in Java are fixed length, so I think what you really want to do is use a List<Tokens>
e.g.
List<Tokens> t = new ArrayList<Tokens>();
and
t.add(new Tokens(...))
unless you know in advance the number of items you'll have.
Initialize it:
// Declaration:
Tokens[] t;
// Initialization:
t = new Tokens[10]; // (Or whatever your desired length is)
You can combine declaration and initialization, and many do. I'm not a fan of doing so, but:
Tokens[] t = new Tokens[10];
You'll have the same issue with htokens.
You may want to look at the List interface (and its various implementations) instead of using an array.
Your code declares that t will represent an array of Tokens.
However, it does not define that array.
Per the Java Documentation, you need a line like:
t = new Tokens[10]; // Or however large the array should be
You are not initializing Tokens t[]; before using it.
EDIT : You need to it as below :
Tokens[] t = new Tokens[100]; // 100 is just an example
Or use List<Tokens>.
The modified code : < as per Brian Agnew's answer >
import java.io.*;
import java.net.*;
import java.util.*;
public class Main {
static class Tokens
{
String name;
int count;
Tokens(String str,int c)
{
name=str;
count=c;
}
}
public static void main(String[] args) {
String url_str,host;
String htokens[];
URL url;
boolean found=false;
List<Tokens> t = new ArrayList<Tokens>();
int i,j,k;
try
{
File f=new File("urlfile.txt");
FileReader fr=new FileReader(f);
BufferedReader br=new BufferedReader(fr);
while((url_str=br.readLine())!=null)
{
url=new URL(url_str);
host=url.getHost();
htokens=host.split("\\.|\\-|\\_|\\~|[0-9]");
for(i=0;i<htokens.length;i++)
{
if(!htokens[i].isEmpty())
{
found=false;
for(j=0;j<t.size();j++)
{
if(htokens[i].equals(t.get(j).name))
{
k=t.get(j).count+1;
t.set(j,new Tokens(htokens[i],k));
found=true;
break;
}
}
if(!found)
{
t.add(new Tokens(htokens[i],1));
}
}
}
}
System.out.println(t.size() + "class tokens :");
for(i=0;i<t.size();i++)
{
System.out.println("name :"+t.get(i).name+" freq :"+t.get(i).count);
}
br.close();
fr.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
Just to mention, you should not use C-like array syntax, i.e. use
String[] names = { "Walter", "Hans", "Bill" };
Instead of
String names[] = { "Walter", "Hans", "Bill" };

Categories