I am trying to create an authentication system of sorts that uses a file called Users.dat to store user data. Currently, I am developing a method to remove users by rewriting the Users.dat file, omitting the user specified. The code below works in a basic environment with an all-encompassing directory containing the .java files and the Users.dat file in the same spot. The old Users.dat file is deleted and Users.dat.tmp is renamed to User.dat. (No problems here, everything works as intended).
public static boolean RemoveUser(String userName) {
// TODO remove username from Users.dat
try {
File originalFile = new File("Users.dat");
System.out.println(originalFile.getAbsolutePath());
BufferedReader read = new BufferedReader(new FileReader("Users.dat"));
String line = null;
while ((line = read.readLine()) != null) {
if (line.indexOf(userName) != -1) {
break;
}
}
String[] userInfo = line.split(", ");
if (!userName.equals(userInfo[2])) {
System.out.println("Username not found. No users removed.");
read.close();
return false;
}
File tempFile = new File(originalFile.getAbsolutePath() + ".tmp");
PrintWriter print = new PrintWriter(new FileWriter(tempFile));
String lineToRemove = line;
BufferedReader read2 = new BufferedReader(new FileReader("Users.dat"));
while ((line = read2.readLine()) != null) {
if (!line.trim().equals(lineToRemove)) {
print.println(line);
print.flush();
}
}
print.close();
read.close();
read2.close();
System.out.println(originalFile.getAbsolutePath());
originalFile.delete(); //This line is not executing correctly
tempFile.renameTo(originalFile); //Nor is this line
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
return true;
}
Users.dat file format:
Joe, Last, jlast, 58c536ed8facc2c2a293a18a48e3e120, true
Sam, sone, samsone, 2c2a293a18a48e3e12058c536ed8facc, false
Jane, Best, jbest, 293a18a48e3e12052058c536ed8facc2c, false
Andrew, Estes, Aestes, 63a490d69aa544fd1272a976014ad570, true
Test, User, tuser, 63a490d69aa544fd1272a976014ad570, true
I have two System.out.println(originalFile.getAbsolutePath()) statements, one at the beginning, one at the end to make sure the path isn't getting screwed up in the process of everything somehow.
Like I said, the code works, however, when I try to implement it in my project, it creates the Users.dat.tmp and it writes the correct data to it, but it does not delete the old Users.dat file, nor does it rename the Users.dat.tmp file to replace Users.dat. I'm certain the directory is correct, as I am literally displaying it as the code executes. I can't figure out any other reason why originalFile.delete() and tempFile.renameTo(originalFile) aren't functioning properly.
EDIT:
Using java.nio.file, I was able to produce an error message. it reads:
java.nio.file.FileSystemException: C:\Path\Users.dat: The process cannot access the file because it is being used by another process.
I don't have the file open when this error message is shown, and I don't get this error using java.nio in my testing environment mentioned at the beginning. I'm not sure what other process the message is referring to.
EDIT 2:
I tried running the code on other machines, one a Mac, the other a Windows laptop, and the code functioned on the Mac just fine, but I was still seeing the same issue on the Windows laptop.
I had the similar issue. My problem was not closing all the streams I read and written to the file. Thanks for your Edit #1, that was helpful
When you wrap
BufferedReader read = new BufferedReader(new FileReader("Users.dat"));
don't you need to close the inner readers too?
If not for the author, but for those who stambled upon this question (like me), hope this suggestion will be useful
I had an earlier function that I was calling in main that was accessing Users.dat, but I never closed the BufferredReader in that function.
Related
I have a requirement to send the sms and email on the trigger of some event.
It's working fine when I am testing with english. But when I change the text to Japanese, it's producing some sort of junk message. I am using java as my programming language.
I have tried some solutions like changing the charset preference and adding -Dfile.encoding=UTF8 in run configurations, but doesn't seem to work.
It's not working in a particular case.
When I hard-code the string in my java class as Japanese string then it's working fine. But when I try to read from property file it's producing some junk characters.
Finally I have solved this. As I have stated in my question itself, that the problem is mainly with reading from .property file. When I tried to hardcode the string it's working perfectly.
As #Henry suggested in his comments, all the .property files contain only ISO8859-1 characters. So, I followed the process to convert string from ISO8859-1 format to UTF.
It can be achieved by simply using this one line of code.
String utf8String = new String(Charsets.ISO_8859_1.encode("your string").array()).
Although, It solved my purpose, But I thought it's not a clean way to solve this.
For my scenario I had to add a new configuration, so instead of going through above way. I kept the string in separate text file and read from the file.
String filePath = "filename.txt"
try {
BufferedReader br = new BufferedReader(new FileReader(filePath));
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
return sb.toString();
} catch (FileNotFoundException e) {
log.error("file not found ", e);
} catch (IOException e) {
log.error("Error occurred ", e);
}
It solved the issue without using any hack to convert from one CharSet to another.
Currently working on a project which requires me to read in file input of over 50k lines. I am currently using the BufferedReader class to read in the input and present the data in a text area. Currently, the application just reproduces the file in my own HMI similar to a text editor, however where I would like to differ is that there are certain starting words for each line that I would like to not be presented in the text area... I believe my lack of experience with buffers is responsible for my problems. I have tried implementing code along the following lines:
private void insertSyrFile(BufferedReader buffer, JFileChooser chooser) throws IOException{
String line;
//reader = "\n";
try{
reader = new FileReader(chooser.getSelectedFile().toString());
buffer = new BufferedReader(reader);
while ((line = buffer.readLine()) != null){
if (!line.startsWith("Elaborating"))
origSyrTextFeild.read(buffer, null);
}
}catch(Exception e){
JOptionPane.showMessageDialog(null, e);
}
}
This code was implemented with the following button event handler:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(null);
syrFile.openFile(chooser.getSelectedFile().toString());
try {
insertSyrFile(buffer, chooser); //origSyrTextFeild.setText(syrFile.readFileLine());
} catch (IOException ex) {
Logger.getLogger(ParsingAppMainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
... using this code, even though I have if statement to check for a string, the original file is still reproduced with no processing on the file. I am still a beginner in java, however if someone understands what my goal is and has any insight I'd appreciate any ideas!!
I guess you may use " origSyrTextFeild.append(line);" instead of " origSyrTextFeild.read(buffer, null);". Because the if statement checks the "line" but "read" method get contents from the original buffer.
I am coding a program that requires me to be able to write the personal details of people to an excel file. I must be able to then read the contents of this file and present them in a combo box. However currently if I run the program and enter the details of a person, then use the combo box to select one of these people, anybody entered on the current run-through of the program will not be shown in the combo box. If I close the program and run it again, however, they will then appear. How can I fix this?
String csvFile = "Clients.csv";
BufferedReader br = null;
String line = "";
String cvsSplitBy = ",";
String fullName = null;
try {
File file = new File("Clients.csv");
br = new BufferedReader(new FileReader(file));
while ((line = br.readLine()) != null) {
String[] data = line.split(cvsSplitBy);
fullName = data[0]+" "+data[1];
comboBox_1.addItem(fullName);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//FILE READING END
comboBox_1.setBounds(130, 25, 584, 20);
existingClients.add(comboBox_1);
When you run your program, your BufferedReader is fed with the csv file with current data in it. In run time your program doesn't know whether you entered new entries in your csv file.
You should write a block of code which updates the csv file when you hit the "Add Person" button(or whatever you call it in your program), then triggers a new BufferedReader.
Edit:
I don't know your program is a gui or a console application, but I will try to explain as if we are talking about a gui.
Step - 1 --> When the user fills the details of a new person in a textarea in your program, or when s/he hits the "Add Person" button, you should store the details of this person.
Step - 2 -->Then you must create a writer instance. This instance must append new data to your csv file;
BufferedWriter writer = new BufferedWriter(new FileWriter(csvFile));
writer.write("\n" + newPersonDataasString + "\n");
Step - 3 -->Finally, you must read your file again using a new BufferedReader fed with your csv file.
as exe-cute-table mentioned, wrapping these steps into custom methods like readFile(), writeFile() is a good solution for maintaining purposes.
Let me now if I misdirected you.
Each time you write in your file, you have to open it again (with the BufferedReader as you did) too see the changes. The BufferedReader, once created, won't store the new changes of your CSV file.
So the best way is to have two functions:
readFile(filename) which will read the file using the BufferedReader (which is created, used and closed)
writeFile(filename, contentToWrite) which will write into the file using the BufferedWriter (which is also created, used and closed)
Each time you add a person, call writeFile("your.csv", your_data).
Each time you want to display the datas from your csv (e.g listing all people stored in), call readFile("your.csv")
I am currently interfacing a GUI to an UCI chess engine. For this purpose i am creating the engine process using:
try {
process = Runtime.getRuntime().exec(enginePath);
} catch (IOException e) {
System.err.println("ENGINE NOT FOUND");
e.printStackTrace();
}
and i am sure that i am able to open the engine.
When engine is opened, there is no significant stream outputted from engine. In order to initiate communication, I have to send specific commands to the engine. The engine will respond then... Therefore it is working in a command/response approach(not immediately streaming data when opened or talking without spoken to). In order to communicate i have a send message block. In this block write a message to the engine using its outputstream and get input using its standart input stream as in the following send method:
private String sendCommand(String command) {
stdin = new PrintWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader errReader = new BufferedReader(newInputStreamReader(process.getErrorStream()));
String answer = "";
stdin.println(command);
stdin.flush();
stdin.close();
try {
String line = "";
while ((line = inputReader.readLine()) != null) {
System.out.println(line);
answer = line;
}
inputReader.close();
} catch (IOException ioe) {
System.err.println("READ ERROR");
ioe.printStackTrace();
}
try {
String line = "";
while ((line = errReader.readLine()) != null) {
System.err.println(line);
}
errReader.close();
} catch (IOException ioe) {
System.err.println("READ ERROR");
ioe.printStackTrace();
}
return answer;
}
By the way the whole engine is working in a single seperate thread other than the main GUI thread. Therefore no overloading for the GUI. However i didnot seperate the stdin stderr and output methods in individual threads since i suppose there will be only stdin and the one that i will write to the engine. For the time being i assume they will not collide.
With these codes i am able to communicate with the engine and i can see the outputs in the console. However due to stdin.close(); i can only use this method once (In the seconds time i have a STREAM CLOSED error). The chess engine is needed to be communicated in command/response approach many times when opened, without restarting the exe in each time. The problem is that if i remove the line : stdin.close(); yes the communication continues, but my console is blocked by this communication. I.e. i cannot println to the console for debugging purposes anymore. Which is very critical because my main debugging weapon is system.out.println. If i do not remove stdin.close(); i have to restart executable each time i want to send message and i do not want that. **The strange part is that i can see the messages coming from the engine in my console due to "System.out.println(line);" line in the send method; however i cannot print anything on the console once the code exits the method. **
EDIT: Actually after this block:
while ((line = inputReader.readLine()) != null) {
System.out.println(line);
answer = line;
}
System.out.println starts not to work.
EDIT: The problem seems not to be with println but any statement after while loop.
Why statements after while loop is not getting executed?
according to this, it seems that since the stream is never closed, "while loop" is stuck(?). Actually when printing inside while loop, at some point(after a stream is finished), the prints stop, which must indicate while loop is finished. Therefore if it is finished, it should continue on the next statements, shouldn't it? Anyway, the messages from the engine had a set of strings at end of each stream; therefore when i encounter one of them i am breaking the while loop.
Note: it is also interesting that : accumulating data as: "receivedString += line"; doesnot work,i.e. data is not accumulated. In order to fix it i luckily made it "receivedString = receivedString + line + "\n""; and it worked.. I dont know why.
You're reading the input until end of stream, so it won't stop reading until end of stream occurs. End of stream means that the peer has closed the connection in this case. That won't happen for a process's output or error stream until the process exits. You'll have to find some other loop termination condition, or else consume the stdout and stderr in separate threads.
In the app I am working on right now, part of the functionality is to write data saved on the device to a flash drive connected via a USB-OTG adapter. Specifically, the device is a rooted Motorola Xoom running 4.2.2. I can successfully write files to the drive and read them on my computer. That part works fine. However, when I try to replace existing files with new information, the resulting files come out empty. I even delete the existing files before writing new data. What's weird is that after copying the contents of my internal file to the flash drive, I log the length of the resulting file. It always matches the input file and is always a non-0 number, yet the file still shows up as blank on my computer. Can anyone help with this problem? Relevant code from the AsyncTask that I have doing this work is below.
#Override
protected Void doInBackground(Void... params) {
File[] files = context.getFilesDir().listFiles();
for (File file : files) {
if (file.isFile()) {
List<String> nameSegments = Arrays.asList(file.getName().split(
"_"));
Log.d("source file", "size: " + file.length());
String destinationPath = "/storage/usbdisk0/"
+ nameSegments.get(0) + "/" + nameSegments.get(1) + "/";
File destinationPathFile = new File(destinationPath);
if (!destinationPathFile.mkdirs()) {
destinationPathFile.mkdirs();
}
File destinationFile = new File(destinationPathFile,
nameSegments.get(2));
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader(file);
fw = new FileWriter(destinationFile, false);
int c = fr.read();
while (c != -1) {
fw.write(c);
c = fr.read();
}
fw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fr.close();
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.d("destination file", "size: " + new File(destinationFile.getPath()).length());
}
}
return null;
}
EDIT:
Per #Simon's suggestion, I added output.flush() to my code. This does not change the result.
EDIT #2:
I did some further testing with this and found something interesting. If I go to Settings->Storage->Unmount USB Storage after writing to the flash drive but before removing it from the OTG adapter, everything works perfectly. However, failing to eject the drive after writing results in the data not being written. What's strange is that the folder structure and file itself are created on the drive, but the file is always empty. One more thing: if I go to a file manager application and open up the file prior to removing the drive, the files all exist as they should. However, even removing the device, plugging it straight back in to the tablet and opening any of the files results in the file looking empty. I can't make heads or tails of this, and this is incredibly frustrating. Can anyone help with this?
EDIT #3:
I also changed to using FileReaders and FileWriters just to wee what would happen. I don't care about efficiency at this point, I simply want file writing to work reliably. This change did not affect the issue. Updated code is posted above.
Try using FileReader.ready() method before your FileReader.read() call,
and ensure if your FileReader really has some bytes in it.
Try this , Used buffered reader for writing
try
{
fw = new FileWriter(destinationFile);
BufferedWriter writer=new BufferedWriter(fw);
writer.append(yourText); // Append can be changed to write or something if you want to overwrite
writer.close();
}
catch (Exception e) {
throw new RuntimeException(e);
}
finally {
if (fw != null) {
try {
fw.flush();
fw.close();
}
catch (IOException e) {
}
I found the solution to my problem. It appears that the Android system buffers some files off of the SD card/flash drive, and then writes them to the flash drive upon eject. The following code after my file operations synchronizes the buffer with the filesystem and allows the flash drive to be immediately removed from the device without data loss. It's worth noting that this DOES require root access; it will not work on a non-rooted device.
try {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("sync; sync\n");
os.writeBytes("exit\n");
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
Source of my solution: Android 2.1 programatically unmount SDCard
It sounds like the filesystem is caching your changes, but not actually writing them to the flash drive until you eject it. I don't think there's a way to flush the filesystem cache, so the best solution seems to be just to unmount and then remount the flash drive.