I'm making an android application that allows a user to add collectibles to a shelf, and the name of each collectible gets held in array called owned. I've written some code (with the help of some folks here) that should save my array into a text file.
That code looks like this:
#Override
public void onStop()
{
try{
super.onStop();
FileOutputStream fOut = openFileOutput("savedVinyls", Context.MODE_PRIVATE);
String vinylString="";
OutputStreamWriter osWriter = new OutputStreamWriter(fOut);
for(int i = 0; i < ownedCounter; i++)
{
if(!owned[i].equals(""))
vinylString += owned[i] + " ";
}
fOut.write(vinylString.getBytes());
fOut.close();
}
catch(IOException OE){
OE.getStackTrace();
}
}
This should, I think, save the array to a file so that it can be read back in later (This part appears to be working correctly, as certain parts of the loading code work)
The code for loading this file back and reading it is as follows:
try{
FileInputStream fileStream;
fileStream = openFileInput("savedVinyls");
byte[] buffer = new byte[1024];
StringBuffer line = new StringBuffer("");
while(fileStream.read(buffer) != -1)
{
line.append(new String(buffer));
}
System.out.println(line);
String readVinyls = line.toString();
String[] splitReader = readVinyls.split(" ");
owned = splitReader;
}
catch(IOException OE)
{
OE.printStackTrace();
}
I may be going about the file reading/writing all the wrong way, my goal is to make it so that when the user closes the app it saves their collection string, and then loads it when the app is loaded next time.
Currently, it crashes when it tries to load the text file.
Any help would be greatly appreciated!
With an ArrayIndexOutOfBoundsException it means you are trying to access an invalid index in the array.
Basically you are calling owned[i] at some point, where i is not a valid index. (Greater than the size of owned)
Related
I have data file “ReadFile1.txt”. I want to read each data from ReadFile1.txt and manipulate those data then write the results in another file “WriteFile2.txt”. Here is my function. The problem is it only reads 2nd,4th, and so on and does write only 2nd result. What’s wrong in this code? I appreciate your help.
public void doManipulate() throws NumberFormatException, IOException {
int multiple = 10;
try {
FileInputStream file = new FileInputStream("ReadFile1.txt");
InputStreamReader input = new InputStreamReader(file);
BufferedReader reader = new BufferedReader(input);
String data1;
while ((data1 = reader.readLine()) != null) {
int data2 = 0;
data1 = reader.readLine();
data2 = Integer.parseInt(data1);
int compressedFrames = data2*multiple;
File file2 = new File("WriteFile2.txt");
FileWriter writer = new FileWriter(file2);
writer.write(String.valueOf(compressedFrames) + "\n");
writer.flush();
writer.close();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
You're calling reader.readLine() twice for every iteration of the while loop - the first time is in the loop declaration, which reads every odd line, and the second is just a couple of lines down (data1 = reader.readLine();). The second call is blowing away anything read by the first before you have a chance to parse it. Removing the second call should fix the "every other line" issue.
Another issue is that you're closing the writer at every iteration of the while loop - don't close the writer until the while loop is done or your output file will only have the first parsed data element in it after your program closes.
I used this code in a different application to write a name and highscore onto the file for my game. Now i'm using this code to get a name and password from a .DAT file and be able to add a new user and password. Here's the .DAT file.
michael123
speaker123
katherine123
motor123
username
password
Here's the code. Reading the file works fine but writing to it does nothing at all and i'm unsure why.
InputStream file;
BufferedReader fileStream;
FileWriter fileWriter;
BufferedWriter fileWrite;
String temp = "";
int users = 0;
public void readUserInfo() throws IOException {
try {
file = Board.class.getResourceAsStream("users.DAT");
fileStream = new BufferedReader(new InputStreamReader(file));
} catch (Exception e) {
System.out.println("File not found");
}
for (int i = 0; i < users; i++) {
temp = fileStream.readLine();
Board.username[i] = temp.trim();
temp = fileStream.readLine();
Board.password[i] = temp.trim();
}
//Close
fileStream.close();
file.close();
}
public void addUser() throws IOException {
fileWriter = new FileWriter(Board.class.getResource("users.DAT").getFile(),true);
fileWrite = new BufferedWriter(fileWriter);
System.out.println("Users : " + users);
//Skip already created users
for (int i = 0; i < users; i++) {
fileWrite.newLine();
fileWrite.append(Board.username[i]);
fileWrite.newLine();
fileWrite.append(Board.password[i]);
}
System.out.println("Adding" + Board.username[users] + " : " + Board.password[users]);
//Add user
fileWrite.newLine();
fileWrite.append(Board.username[users]);
fileWrite.newLine();
fileWrite.append(Board.password[users]);
//Close
fileWrite.close();
System.out.println("Closed fileWrite");
}
I'm using netbeans. The file being read from is in the same package as all the other classes.
Maybe you have packaged your jar with some state of the file users.DAT (a defined set of users) and when you read them from classpath you see only the users from the time you have created the jar. The writing goes then to another file.
You should read the user from the filesystem too.
Check the working directory of your app there should be correct file containing the users added.
Also no need for copying all the user over and over again every time you add one, just open your file in append mode
fileWriter = new FileWriter(new File("users.DAT"), true);
Unless you want to be able to delete users, in that case keep everything in memory and save when you exit the program or explicitly with a save action.
In your reading you use file = Board.class.getResourceAsStream("users.DAT"); in your writing you just create a file new File("users.DAT") what about changing your addUser() to
public void addUser() throws IOException {
fileWriter = new FileWriter(Board.class.getResource("users.DAT").getFile());
....
}
Edit: The problem is that during writing you are not retrieving the same file as before. I would add this method
public File getUserDataFile() {
return new File(Board.class.getResource("").getFile(), "users.DATA");
}
// then use it like this
new FileWriter(getUserDataFile());
// and
new BufferedReader(new InputStreamReader(getUserDataFile()));
then access it whenever you want to read and write to your file. The problem is Board.class.getResourceAsStream("users.DAT") will return null if your file doesnt exist.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I guess this comes down to reading and writing to the same file. I would like to be able to return the same text file as is input, but with all integer values quadrupled. Should I even be attempting this with Java, or is it better to write to a new file and overwrite the original .txt file?
In essence, I'm trying to transform This:
12
fish
55 10 yellow 3
into this:
48
fish
220 40 yellow 12
Here's what I've got so far. Currently, it doesn't modify the .txt file.
import java.io.*;
import java.util.Scanner;
public class CharacterStretcher
{
public static void main(String[] args)
{
Scanner keyboard = new Scanner( System.in );
System.out.println("Copy and paste the path of the file to fix");
// get which file you want to read and write
File file = new File(keyboard.next());
File file2 = new File("temp.txt");
BufferedReader reader;
BufferedWriter writer;
try {
// new a writer and point the writer to the file
FileInputStream fstream = new FileInputStream(file);
// Use DataInputStream to read binary NOT text.
reader = new BufferedReader(new InputStreamReader(fstream));
writer = new BufferedWriter(new FileWriter(file2, true));
String line = "";
String temp = "";
int var = 0;
int start = 0;
System.out.println("000");
while ((line = reader.readLine()) != null)
{
System.out.println("a");
if(line.contains("="))
{
System.out.println("b");
var = 0;
temp = line.substring(line.indexOf('='));
for(int x = 0; x < temp.length(); x++)
{
System.out.println(temp.charAt(x));
if(temp.charAt(x)>47 && temp.charAt(x)<58) //if 0<=char<=9
{
if(start==0)
start = x;
var*=10;
var+=temp.indexOf(x)-48; //converts back into single digit
}
else
{
if(start!=0)
{
temp = temp.substring(0, start) + var*4 + temp.substring(x);
//writer.write(line.substring(0, line.indexOf('=')) + temp);
//TODO: Currently writes a bunch of garbage to the end of the file, how to write in the middle?
//move x if var*4 has an extra digit
if((var<10 && var>2)
|| (var<100 && var>24)
|| (var<1000 && var>249)
|| (var<10000 && var>2499))
x++;
}
//start = 0;
}
System.out.println(temp + " " + start);
}
if(start==0)
writer.write(line);
else
writer.write(temp);
}
}
System.out.println("end");
// writer the content to the file
//writer.write("I write something to a file.");
// always remember to close the writer
writer.close();
//writer = null;
file2.renameTo(file); //TODO: Not sure if this works...
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Given that this is a pretty quick and simple hack of a formatted text file, I don't think you need to be too clever about it.
Your logic for deciding whether you are looking at a number is pretty complex and I'd say it's overkill.
I've written up a basic outline of what I'd do in this instance.
It's not very clever or impressive, but should get the job done I think.
I've left out the overwriting and reading the input form the console so you get to do some of the implementation yourself ;-)
import java.io.*;
public class CharacterStretcher {
public static void main(String[] args) {
//Assumes the input is at c:\data.txt
File inputFile = new File("c:\\data.txt");
//Assumes the output is at c:\temp.txt
File outputFile = new File("c:\\temp.txt");
try {
//Construct a file reader and writer
final FileInputStream fstream = new FileInputStream(inputFile);
final BufferedReader reader = new BufferedReader(new InputStreamReader(fstream));
final BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile, false));
//Read the file line by line...
String line;
while ((line = reader.readLine()) != null) {
//Create a StringBuilder to build our modified lines that will
//go into the output file
StringBuilder newLine = new StringBuilder();
//Split each line from the input file by spaces
String[] parts = line.split(" ");
//For each part of the input line, check if it's a number
for (String part : parts) {
try {
//If we can parse the part as an integer, we assume
//it's a number because it almost certainly is!
int number = Integer.parseInt(part);
//We add this to out new line, but multiply it by 4
newLine.append(String.valueOf(number * 4));
} catch (NumberFormatException nfEx) {
//If we couldn't parse it as an integer, we just add it
//to the new line - it's going to be a String.
newLine.append(part);
}
//Add a space between each part on the new line
newLine.append(" ");
}
//Write the new line to the output file remembering to chop the
//trailing space off the end, and remembering to add the line
//breaks
writer.append(newLine.toString().substring(0, newLine.toString().length() - 1) + "\r\n");
writer.flush();
}
//Close the file handles.
reader.close();
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
You may want to consider one of these:
Build the new file in memory, rather than trying to write to the same file you are reading from. You could use StringBuilder for this.
Write to a new file, then overwrite the old file with the new one. This SO Question may help you there.
With both of these, you will be able to see your whole output, separate from the input file.
Additionally, with option (2), you don't have the risk of the operation failing in the middle and giving you a messed up file.
Now, you certainly can modify the file in-place. But it seems like unnecessary complexity for your case, unless you have really huge input files.
At the very least, if you try it this way first, you can narrow down on why the more complicated version is failing.
You cannot read and simultaneously write to the same file, because this would modify the text you currently read. This means, you must first write a modified new file and later rename it to the original one. You probably need to remove the original file before renameing.
For renaming, you can use File.renameTo or see one of the many SO's questions
You seem to parse integers in your code by collecting single digits and adding them up. You should consider using either a Scanner.nextInt or employ Integer.parseInt.
You can read your file line by line, split the words at white space and then parse them and check if it is either an integer or some other word.
This is basically what I am trying to do.
I wanna take a File
Turn it into a Byte Array
Turn it into a String
Store it in a MySQL Table
Retrieve the String
Turn it back into a Byte Array
Turn it back into a File
Now, I have some code for you, which I tried to comment as best as I could. My problem is, that the file I get at the end of this code, doesn't come out right. It's missing information. It's a text file, so I should be able to tell whether the file is complete or not.
As far as I can see, it looks like I only get the last part of the file, and not the entire file. I am pretty sure I messing something up badly somewhere in this conversion. If you got suggestions on how to do this conversion and retrieval more efficiently (Still keeping the Database and all that in mind), please let me know as well!
The code is listed below
import java.io.*;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
public class main {
public static void main(String[] args) {
// The file we want to save.
File f = new File("build.xml");
try {
// Make it into a byte array first
FileInputStream fis = new FileInputStream(f);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
try {
for(int readNum; (readNum = fis.read(buf)) != -1;) {
bos.write(buf, 0, readNum);
System.out.println("read " + readNum + " bytes,");
}
StringBuilder s = new StringBuilder();
// Now we simulate making it into a String, for easier storage
// in a database.
for(byte b : buf) {
// for debugging
s.append(b).append(",");
System.out.print(b +",");
}
// Now we want to retrieve the file from the database as a string
File someFile = new File("build2.xml");
FileOutputStream fos = new FileOutputStream(someFile);
// We count how many bytes there are in this string.
// One byte per Token.
StringTokenizer st = new StringTokenizer(s.toString(),",");
buf = new byte[st.countTokens()];
int i = 0;
StringBuilder t = new StringBuilder();
// Now we parse out all Bytes from the string, and put them into
// the prepared byte array.
while(st.hasMoreTokens()) {
byte b = Byte.parseByte(st.nextToken());
System.out.print(b + ",");
buf[i] = b;
i++;
// for debugging
t.append(b).append(",");
}
// Here I print true if both strings are exactly the same
// which they should be, which means that the bytes are intact
// before and after conversion.
System.out.println("\n" +(t.toString().equals(s.toString()) ? true : false));
// Here we would make the physical file on the machine.
fos.write(buf);
fos.flush();
fos.close();
} catch (IOException ex) {
Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
http://pastebin.com/699yuE8f
Your approach is totally ignoring encodings, which is not a good thing. Characters are not equal to or equivalent to bytes.
If you have to do it in the sequence you describe, then create the string by something like this:
String intermediateString = new String(theByteArray,
theSameEncodingTheFileWasCreatedWith);
Likewise, when you convert the string back into bytes, get the bytes like this:
byte[] bytesToSave = intermediateString.getBytes(theSameEncodingTheFileWasCreatedWith);
But besides any of that, what's the point of using the string at all? Why not just store the bytes right into the database?
You simply messed up the string creation, and you don't read the bos but the buf.
for(byte b : >>buf<<) {
// for debugging
s.append(b).append(",");
System.out.print(b +",");
}
Otherwise I am not convinced that it will work or it is a good solution. Why can't you just store it simply in the database?
The code you shared is IMHO more complicated as it had to be.
Why do you read your text on byte-level if you are only interested in it's String representation?
I would prefer to read the file using an InputStreamReader. That allows you to directly operate on characters.
I have a text file that I want to edit using Java. It has many thousands of lines. I basically want to iterate through the lines and change/edit/delete some text. This will need to happen quite often.
From the solutions I saw on other sites, the general approach seems to be:
Open the existing file using a BufferedReader
Read each line, make modifications to each line, and add it to a StringBuilder
Once all the text has been read and modified, write the contents of the StringBuilder to a new file
Replace the old file with the new file
This solution seems slightly "hacky" to me, especially if I have thousands of lines in my text file.
Anybody know of a better solution?
I haven't done this in Java recently, but writing an entire file into memory seems like a bad idea.
The best idea that I can come up with is open a temporary file in writing mode at the same time, and for each line, read it, modify if necessary, then write into the temporary file. At the end, delete the original and rename the temporary file.
If you have modify permissions on the file system, you probably also have deleting and renaming permissions.
if the file is just a few thousand lines you should be able to read the entire file in one read and convert that to a String.
You can use apache IOUtils which has method like the following.
public static String readFile(String filename) throws IOException {
File file = new File(filename);
int len = (int) file.length();
byte[] bytes = new byte[len];
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
assert len == fis.read(bytes);
} catch (IOException e) {
close(fis);
throw e;
}
return new String(bytes, "UTF-8");
}
public static void writeFile(String filename, String text) throws IOException {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filename);
fos.write(text.getBytes("UTF-8"));
} catch (IOException e) {
close(fos);
throw e;
}
}
public static void close(Closeable closeable) {
try {
closeable.close();
} catch(IOException ignored) {
}
}
You can use RandomAccessFile in Java to modify the file on one condition:
The size of each line has to be fixed otherwise, when new string is written back, it might override the string in the next line.
Therefore, in my example, I set the line length as 100 and padding with space string when creating the file and writing back to the file.
So in order to allow update, you need to set the length of line a little larger than the longest length of the line in this file.
public class RandomAccessFileUtil {
public static final long RECORD_LENGTH = 100;
public static final String EMPTY_STRING = " ";
public static final String CRLF = "\n";
public static final String PATHNAME = "/home/mjiang/JM/mahtew.txt";
/**
* one two three
Text to be appended with
five six seven
eight nine ten
*
*
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException
{
String starPrefix = "Text to be appended with";
String replacedString = "new text has been appended";
RandomAccessFile file = new RandomAccessFile(new File(PATHNAME), "rw");
String line = "";
while((line = file.readLine()) != null)
{
if(line.startsWith(starPrefix))
{
file.seek(file.getFilePointer() - RECORD_LENGTH - 1);
file.writeBytes(replacedString);
}
}
}
public static void createFile() throws IOException
{
RandomAccessFile file = new RandomAccessFile(new File(PATHNAME), "rw");
String line1 = "one two three";
String line2 = "Text to be appended with";
String line3 = "five six seven";
String line4 = "eight nine ten";
file.writeBytes(paddingRight(line1));
file.writeBytes(CRLF);
file.writeBytes(paddingRight(line2));
file.writeBytes(CRLF);
file.writeBytes(paddingRight(line3));
file.writeBytes(CRLF);
file.writeBytes(paddingRight(line4));
file.writeBytes(CRLF);
file.close();
System.out.println(String.format("File is created in [%s]", PATHNAME));
}
public static String paddingRight(String source)
{
StringBuilder result = new StringBuilder(100);
if(source != null)
{
result.append(source);
for (int i = 0; i < RECORD_LENGTH - source.length(); i++)
{
result.append(EMPTY_STRING);
}
}
return result.toString();
}
}
If the file is large, you might want to use a FileStream for output, but that seems pretty much like it is the simplest process to do what you're asking (and without more specificity i.e. on what types of changes / edits / deletions you're trying to do, it's impossible to determine what more complicated way might work).
No reason to buffer the entire file.
Simply write each line as your read it, insert lines when necessary, delete lines when necessary, replace lines when necessary.
Fundamentally, you will not get around having to recreate the file wholesale, especially if it's just a text file.
What kind of data is it? Do you control the format of the file?
If the file contains name/value pairs (or similar), you could have some luck with Properties, or perhaps cobbling together something using a flat file JDBC driver.
Alternatively, have you considered not writing the data so often? Operating on an in-memory copy of your file should be relatively trivial. If there are no external resources which need real time updates of the file, then there is no need to go to disk every time you want to make a modification. You can run a scheduled task to write periodic updates to disk if you are worried about data backup.
In general you cannot edit the file in place; it's simply a very long sequence of characters, which happens to include newline characters. You could edit in place if your changes don't change the number of characters in each line.
Can't you use regular expressions, if you know what you want to change ? Jakarta Regexp should probably do the trick.
Although this question was a time ago posted, I think it is good to put my answer here.
I think that the best approach is to use FileChannel from java.nio.channels package in this scenario. But this, only if you need to have a good performance! You would need to get a FileChannel via a RandomAccessFile, like this:
java.nio.channels.FileChannel channel = new java.io.RandomAccessFile("/my/fyle/path", "rw").getChannel();
After this, you need a to create a ByteBuffer where you will read from the FileChannel.
this looks something like this:
java.nio.ByteBuffer inBuffer = java.nio.ByteBuffer.allocate(100);
int pos = 0;
int aux = 0;
StringBuilder sb = new StringBuilder();
while (pos != -1) {
aux = channel.read(inBuffer, pos);
pos = (aux != -1) ? pos + aux : -1;
b = inBuffer.array();
sb.delete(0, sb.length());
for (int i = 0; i < b.length; ++i) {
sb.append((char)b[i]);
}
//here you can do your stuff on sb
inBuffer = ByteBuffer.allocate(100);
}
Hope that my answer will help you!
I think, FileOutputStream.getFileChannel() will help a lot, see FileChannel api
http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html
private static void modifyFile(String filePath, String oldString, String newString) {
File fileToBeModified = new File(filePath);
StringBuilder oldContent = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(fileToBeModified))) {
String line = reader.readLine();
while (line != null) {
oldContent.append(line).append(System.lineSeparator());
line = reader.readLine();
}
String content = oldContent.toString();
String newContent = content.replaceAll(oldString, newString);
try (FileWriter writer = new FileWriter(fileToBeModified)) {
writer.write(newContent);
}
} catch (IOException e) {
e.printStackTrace();
}
}
You can change the txt file to java by saving on clicking "Save As" and saving *.java extension.