I have an application that can create backups of its information and recover them. I was working on a seventh version, and found that the recovery method would not work. It acted as if it did, but would do nothing. I could not figure out what was causing this, so I decided to simply start over from my sixth version.
None of my versions' recovery methods work now, despite passing all tests in the past.
It does not throw an error or anything else. It tells the user "The backup has been restored." with a toast. If ext storage isn't allowed, it throws an error. If the file path doesn't exist, throws an error. Nothing abnormal on logcat. But when everything's right, it just simply doesn't work. So...here's the recovery method from a stable version. Let me know if there's anything else you'd like to examine.
Edit: Changed method of decoding from Base64 and setting it to a string. End result still same. Narrowed down issue to the while loop, which never runs, so no information is actually processed.
//Method025: Imports user acc settings from a file on a specified path.
public void importFile() {
//The file variable to be imported.
File file;
try {
//Used to access settings.
TinyDB database = new TinyDB(getApplicationContext());
//Sets the file equal to the file found at the specified path.
String strfilePath = database.getString("FilePath");
file = new File(strfilePath);
//To be used to arrange the imported information.
ArrayList<String> strAcc = new ArrayList<>();
ArrayList<String> strUser = new ArrayList<>();
ArrayList<String> strPass = new ArrayList<>();
ArrayList<String> strAdditionalInfo = new ArrayList<>();
//To be used to store all the information for additional info variables. This is
//due to its multi-line nature requiring a slightly different method of
//importation, the other variables are expected to be one line.
String strExtraInfo = "";
//Goes through the file and adds info to arrays for each corresponding variable.
//If the line does not have an identifier, it assumes it to be an additional
//info line, and will be processed later.
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
String strLine = br.readLine();
//Decodes the line from Base64 and converts it to a string.
byte[] decodedContent = Base64.decode(strLine.getBytes(), Base64.DEFAULT);
strLine = new String (decodedContent);
while ((line = br.readLine()) != null) {
if (strLine.contains("[Acc]")) {
strLine = strLine.replace("[Acc]","");
strAcc.add(strLine);
} else if (strLine.contains("[User]")) {
strLine = strLine.replace("[User]", "");
strUser.add(strLine);
} else if (strLine.contains("[Pass]")) {
strLine = strLine.replace("[Pass]", "");
strPass.add(strLine);
} else {
strExtraInfo += strLine;
}
}
}
The issue was completely different from first believed, and there ended up being many problems. The main ones are as listed.
I assume passing the tests in the past was on account of human error, and the question has been changed to reflect that.
Incorrect method of decoding Base64
Converting to Base64 and back messed up line spacing
ReadLine() can only be called once, doing so more returns nothing
Not enough error checking for things such as strAdditionalInfo.size > 0
Substring recovery method throws many errors, as can be done more simply using split()
Here is the updated code, fully functional.
public void importFile() {
//The file variable to be imported.
File file;
try {
//Used to access settings.
TinyDB database = new TinyDB(getApplicationContext());
//Sets the file equal to the file found at the specified path.
String strfilePath = database.getString("FilePath");
file = new File(strfilePath);
//To be used to arrange the imported information.
ArrayList<String> strAcc = new ArrayList<>();
ArrayList<String> strUser = new ArrayList<>();
ArrayList<String> strPass = new ArrayList<>();
ArrayList<String> strAdditionalInfo = new ArrayList<>();
//To be used to store all the information for additional info variables. This is
//due to its multi-line nature requiring a slightly different method of
//importation, the other variables are expected to be one line.
String strExtraInfo = "";
//Goes through the file and adds info to arrays for each corresponding variable.
//If the line does not have an identifier, it assumes it to be an additional
//info line, and will be processed later.
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
String strLine;
while ((line = br.readLine()) != null) {
if (line.contains("[Acc]")) {
strLine = line.replace("[Acc]","");
strAcc.add(strLine);
} else if (line.contains("[User]")) {
strLine = line.replace("[User]", "");
strUser.add(strLine);
} else if (line.contains("[Pass]")) {
strLine = line.replace("[Pass]", "");
strPass.add(strLine);
} else {
strExtraInfo += line;
}
}
}
//Gets the list of accounts.
ArrayList<String> savedInfo = new ArrayList<>(database.getListString("allSaved"));
//To be used to get the AdditionalInfo variables one line at a time.
String strSubInfo;
//Gets rid of any erroneous spaces.
while (strExtraInfo.contains(" ")) {
strExtraInfo = strExtraInfo.replace(" ", " ");
}
Log.d("STRExtraInfo",strExtraInfo);
strExtraInfo = strExtraInfo.replace("[ExtraStart]","");
String array[] = strExtraInfo.split("\\[ExtraEnd\\]");
ArrayList<String> strRawAdditionalInfo = new ArrayList<>();
strRawAdditionalInfo = new ArrayList<>(Arrays.asList(array));
for (String info : strRawAdditionalInfo){
strAdditionalInfo.add(info);
Log.d("ExtraInfo",info );
}
//Arranges the information.
for (String name : strAcc) {
savedInfo.add(name);
ArrayList<String> allInfo = new ArrayList<>();
//Gets the info then adds it to database.
//Deletes the old information.
if (strUser.size() > 0) {
allInfo.add(strUser.get(0));
strUser.remove(0);
}
if (strPass.size() > 0) {
allInfo.add(strPass.get(0));
strPass.remove(0);
}
if (strAdditionalInfo.size() > 0) {
allInfo.add(strAdditionalInfo.get(0));
strAdditionalInfo.remove(0);
}
database.putListString(name,allInfo);
}
Related
I'm trying to end up with a results.txt minus any matching items, having successfully compared some string inputs against another .txt file. Been staring at this code for way too long and I can't figure out why it isn't working. New to coding so would appreciate it if I could be steered in the right direction! Maybe I need a different approach? Apologies in advance for any loud tutting noises you may make. Using Java8.
//Sending a String[] into 'searchFile', contains around 8 small strings.
//Example of input: String[]{"name1","name2","name 3", "name 4.zip"}
^ This is my exclusions list.
public static void searchFile(String[] arr, String separator)
{
StringBuilder b = new StringBuilder();
for(int i = 0; i < arr.length; i++)
{
if(i != 0) b.append(separator);
b.append(arr[i]);
String findME = arr[i];
searchInfo(MyApp.getOptionsDir()+File.separator+"file-to-search.txt",findME);
}
}
^This works fine. I'm then sending the results to 'searchInfo' and trying to match and remove any duplicate (complete, not part) strings. This is where I am currently failing. Code runs but doesn't produce my desired output. It often finds part strings rather than complete ones. I think the 'results.txt' file is being overwritten each time...but I'm not sure tbh!
file-to-search.txt contains: "name2","name.zip","name 3.zip","name 4.zip" (text file is just a single line)
public static String searchInfo(String fileName, String findME)
{
StringBuffer sb = new StringBuffer();
try {
BufferedReader br = new BufferedReader(new FileReader(fileName));
String line = null;
while((line = br.readLine()) != null)
{
if(line.startsWith("\""+findME+"\""))
{
sb.append(line);
//tried various replace options with no joy
line = line.replaceFirst(findME+"?,", "");
//then goes off with results to create a txt file
FileHandling.createFile("results.txt",line);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
What i'm trying to end up with is a result file MINUS any matching complete strings (not part strings):
e.g. results.txt to end up with: "name.zip","name 3.zip"
ok with the information I have. What you can do is this
List<String> result = new ArrayList<>();
String content = FileUtils.readFileToString(file, "UTF-8");
for (String s : content.split(", ")) {
if (!s.equals(findME)) { // assuming both have string quotes added already
result.add(s);
}
}
FileUtils.write(newFile, String.join(", ", result), "UTF-8");
using apache commons file utils for ease. You may add or remove spaces after comma as per your need.
I'm currently working on a program that reads in a preset text file and then manipulates the data in various ways. I've got the data manipulation to work with some dummy data but I still need to get the text file read in correctly.
The test file looks like this for 120 lines:
Aberdeen,Scotland,57,9,N,2,9,W,5:00,p.m. Adelaide,Australia,34,55,S,138,36,E,2:30,a.m. Algiers,Algeria,36,50,N,3,0,E,6:00,p.m.(etc etc)
So each of these needs to be read into its own array, in order String[] CityName,String[] Country,int[] LatDeg,int[] LatMin,String[] NorthSouth,int[] LongDeg,int LongMin,String[] EastWest,int[] Time.String[] AMPM
So the problem is that while I'm reasonably comfortable with buffered readers, designing this particular function has proven difficult. In fact, I've been drawing a blank for the past few hours. It seems like it would need multiple loops and counters but I can't figure out the precisely how.
I am assuming that you have one city per line type of file structure. If it is not, it will require a bit of tweaking in the following solution:
I will do the following way if I am more comfortable with BufferReader as you say:
List<List<String>> addresses = new ArrayList<List<String>>();
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
for(String line; (line = br.readLine()) != null; ) {
addresses.add(line.split(","));
}
}
Later, let's say you want to retrieve the country information of say 'Adelaid', you can try the following:
for (List<String> cityInfo : addresses) {
if("Adelaid".equals(cityInfo.get(0)) {
country = cityInfo.get(1);
}
}
Instead of creating different arrays (like String[] CityName,String[] Country, etc.,), try using a Domain Object.
Here, you can have a Domain object or Custom class Location with attributes
public class Location
{
private String cityName;
private String country;
private String latDeg;
etc
getters();
setters();
}`
Then you can write a file reader, each line item in the file will be a Location. So result will have
Location[] locations;
or
List locations;`
To carry out this task I should think the first thing you want to do is establish how many lines of data actually exist within the data file. You say it is 120 lines but what if it happens that it will be more or less? We would want to know exactly what it is so as to properly initialize all our different Arrays. We can use a simple method to accomplish this, let's call it the getFileLinesCount() method which will ulitmately return a Integer value that would be the number of text lines the data file holds:
private int getFileLinesCount(final String filePath) {
int lines = 0;
try{
File file =new File(filePath);
if(file.exists()){
FileReader fr = new FileReader(file);
try (LineNumberReader lnr = new LineNumberReader(fr)) {
while (lnr.readLine() != null){ lines++; }
}
}
else {
throw new IllegalArgumentException("GetFileLinesCount() Method Error!\n"
+ "The supplied file path does not exist!\n(" + filePath + ")");
}
}
catch(IOException e){ e.printStackTrace(); }
return lines;
}
Place this method somewhere within your main class. Now you need to Declare and initialize all your Arrays:
String filePath = "C:\\My Files\\MyDataFile.txt";
int lines = getFileLinesCount(filePath);
String[] CityName = new String[lines];
String[] Country = new String[lines];
int[] LatDeg = new int[lines];
int[] LatMin = new int[lines];
String[] NorthSouth = new String[lines];
int[] LongDeg = new int[lines];
int[] LongMin = new int[lines];
String[] EastWest = new String[lines];
int[] Time = new int[lines];
String[] AMPM = new String[lines];
Now to fill up all those Arrays:
public static void main(String args[]) {
loadUpArrays();
// Do whatever you want to do
// with all those Arrays.....
}
private void loadUpArrays() {
// Read in the data file.
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String sCurrentLine;
int x = 0;
// Read in one line at a time and Fill the Arrays...
while ((sCurrentLine = br.readLine()) != null) {
// Split each line read into an array upon itself.
String[] fileLine = sCurrentLine.split(",");
// Fill our required Arrays...
CityName[x] = fileLine[0];
Country[x] = fileLine[1];
LatDeg[x] = Integer.parseInt(fileLine[2]);
LatMin[x] = Integer.parseInt(fileLine[3]);
NorthSouth[x] = fileLine[4];
LongDeg[x] = Integer.parseInt(fileLine[5]);
LongMin[x] = Integer.parseInt(fileLine[6]);
EastWest[x] = fileLine[7];
Time[x] = Integer.parseInt(fileLine[8]);
AMPM[x] = fileLine[9];
x++;
}
br.close();
}
catch (IOException ex) { ex.printStackTrace(); }
}
Now, I haven't tested this, I just quickly punched it out but I think you can get the jest of it.
EDIT:
As #Mad Physicist has so graciously pointed out within his comment below, a List can be used to eliminate the need to count file lines therefore eliminating the need to read the data file twice. All the file lines can be placed into the List and the number of valid file lines can be determined by the size of the List. Filling of your desired arrays can now also be achieved by iterating through the List elements and processing the data accordingly. Everything can be achieved with a single method we'll call fillArrays(). Your Arrays declaration will be a little different however:
String[] CityName;
String[] Country;
int[] LatDeg;
int[] LatMin;
String[] NorthSouth;
int[] LongDeg;
int[] LongMin;
String[] EastWest;
String[] Time;
String[] AMPM;
public static void main(String args[]) {
fillArrays("C:\\My Files\\MyDataFile.txt");
// Whatever you want to do with all
// those Arrays...
}
private void fillArrays(final String filePath) {
List<String> fileLinesList = new ArrayList<>();
try{
File file = new File(filePath);
if(file.exists()){
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String strg;
while((strg = br.readLine()) != null){
// Make sure there is no blank line. If not
// then add line to List.
if (!strg.equals("")) { fileLinesList.add(strg); }
}
br.close();
}
}
else {
throw new IllegalArgumentException("GetFileLinesCount() Method Error!\n"
+ "The supplied file path does not exist!\n(" + filePath + ")");
}
// Initialize all the Arrays...
int lines = fileLinesList.size();
CityName = new String[lines];
Country = new String[lines];
LatDeg = new int[lines];
LatMin = new int[lines];
NorthSouth = new String[lines];
LongDeg = new int[lines];
LongMin = new int[lines];
EastWest = new String[lines];
Time = new String[lines];
AMPM = new String[lines];
// Fill all the Arrays...
for (int i = 0; i < fileLinesList.size(); i++) {
String[] lineArray = fileLinesList.get(i).split(",");
CityName[i] = lineArray[0];
Country[i] = lineArray[1];
LatDeg[i] = Integer.parseInt(lineArray[2]);
LatMin[i] = Integer.parseInt(lineArray[3]);
NorthSouth[i] = lineArray[4];
LongDeg[i] = Integer.parseInt(lineArray[5]);
LongMin[i] = Integer.parseInt(lineArray[6]);
EastWest[i] = lineArray[7];
Time[i] = lineArray[8];
AMPM[i] = lineArray[9];
}
}
catch(IOException e){ e.printStackTrace(); }
}
On another note...your Time Array can not be Integer since in data, what is considered the time contains a colon (:) which is a alpha character therefore (in case you haven't noticed) I have changed its declaration to String[]
Why do i only get one entry into the map when i run this code.There is thousands of lines in the file im reading in but it only seems to be getting to the first line and stopping?
public class Details {
public Map<String, String> dictionaryWords() throws IOException{
String cvsSplitBy = ",";
Collection<String> words = new TreeSet<String>();
Map<String,String> m = new TreeMap<String,String>();
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("dictionary.csv")));
String line = null;
String [] word = null;
String remove = null;
String nextline = null;
String getAllLines = "-";
while ((line = br.readLine())!= null) {
if (line.startsWith("\"")) {
getAllLines = line;
while((nextline = br.readLine())!= null){
if(!nextline.startsWith("\"")){
getAllLines.concat(nextline);
}else{
}
words.add(getAllLines);
word = getAllLines.split(cvsSplitBy);
remove = word[0].replace('"', '-');
m.put(remove.toLowerCase(),Arrays.toString(word));
}
}else{
}
}
for (String key : m.keySet()) {
System.out.println(key + " " + m.get(key));}
return m;
}
Try the following code
if(!nextline.startsWith("\""))
{
getAllLines = getAllLines.concat(nextline);
}
Don't forget to reassign "getAllLines" to the return value of the .concat() function. Since Strings are immutable, the .concat() function returns a new String object, which you do not assign to anything (therefore it is lost). This leaves you with your original String still stored in "getAllLines" as if the call to .concat() was never made.
Feel Free to use the StringBuilder class and the append method, which will likely be much faster than creating new Strings via .concat() thousands of times.
Also: You do not need blank else{} statements.
In the following part of your code the nextlines (2nd ...) are lost in space. They are saved in the variable nextline and used as a parameter for getAllLines.concat. But the return value of String::concat is not assigned to anything.
...
while((nextline = br.readLine())!= null){
if(!nextline.startsWith("\"")){
getAllLines.concat(nextline);
}else{
...
I'm pretty new to Java (currently enrolled in my first programming class), so the answer to my question could be right in front of me.
My goal is to read in a text file that reads as follows:
4563123,112211324135412
2312311,222121324135211
2312345,112211324135421
5527687,212111313124412
7867567,111111111111111
where the first set of numbers is an ID, and the second set is a set of answers to a test (of which I have the key). Once I've read in the answers I need to store them in an array (and I assume just an array, as my class has not covered ArrayLists yet). All of this data would need to be stored in one array, since I need to return it at the end of the method.
Here is the code that I have so far:
public static String[] readFile(String filename)throws IOException{
Scanner inFile = new Scanner(filename);
String line;
String[] results = new String[101];
int i = 0;
while (inFile.hasNextLine()){
line = inFile.nextLine();
String[] incoming = line.split(",");
String wid = incoming[0];
String answer = incoming[1];
results[i] = wid;
results[i + 1] = answer;
i += 2;
}
inFile.close();
return results;
}
It's safe to ignore the String filename, it was passed in from the main.
Every time I run this method, I keep running into an ArrayOutOfBoundsException, mainly when I try to assign incoming[1] to answer.
I've been staring at this code longer than what is probably good for me, but it seems that I just can't wrap my head around it. Any help would be appreciated, whether that be telling me what is wrong or what I can do to improve.
Since you are using Java 7, use the new Files API and a try-with-resources statement; also, avoid copying empty lines:
final Path file = Paths.get(filename);
String line;
String[] incoming;
String[] results = new String[101];
int nrElements = 0;
try (
final BufferedReader reader = Files.newBufferedReader(path,
StandardCharsets.UTF_8);
) {
while ((line = reader.readLine()) != null) {
incoming = line.split(",");
if (incoming.length != 2)
continue;
results[nrElements++] = incoming[0];
results[nrElements++] = incoming[1];
}
}
return Arrays.copyOfRange(results, 0, nrElements);
Either you are having an empty line in your file. Or a garbage line that doesn't have any comma in it. So before accessing the slitted array, just give a check.
if(incoming != null && incoming.length >= 2){
String wid = incoming[0];
String answer = incoming[1];
// ... other dependent codes go here!
}
It will help you to avoid the Exception.
The code I have produced is meant to provide functionality of reading a text file line by line, saving each line into an array. It seems to read in each line correctly but when I use the printProps() method it only displays one...
Code is only saving one line of a text file to the array, what's wrong with my code?
/*reading in each line of text from text file and passing it to the processProperty() method.*/
Public void readProperties(String filename) {
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
int i = 0;
String line;
line = reader.readLine();
while (line != null && !line.equals("")) {
i++;
processProperty(line);
line = reader.readLine();
}
System.out.println("" + i + " properties read");
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
/*Breaks up the line of text in order to save the value to an array (at this point it only saves one line to the array). org.newProp(newProp) passes the new property to the Organize class where it saves it to an array.
public void processProperty(String line) {
org = new Organize();
int id = nextPropertyID;
nextPropertyID++;
String[] parts = line.split(":");
int propNo = Integer.parseInt(parts[0]);
String postcode = parts[1];
String type = parts[2];
int bedrooms = Integer.parseInt(parts[3]);
int year = Integer.parseInt(parts[4]);
int rental = Integer.parseInt(parts[5]);
Landlord landlord = theLandlord;
Tenant tenant = null;
org.propUniqueCheck(id);
propNoCheck(propNo, postcode);
postcodeCheck(postcode,propNo);
typeCheck(postcode, propNo, type);
bedroomsCheck(bedrooms, postcode, propNo);
yearCheck(propNo, postcode, year);
System.out.println("Creating property " + id);
Property newProp = new Property(id, propNo, postcode, type, bedrooms, year,
rental, landlord, tenant);
org.newProp(newProp);
org.printProps();
}
/*From here down it is the code to save the value to the array*/
public Organize() {
props = new ArrayList<Property>();
PTs = new ArrayList<PotentialTenant>();
waitingList = new LinkedList<String>();
//myList.add(new prop(Property.toString()));
}
public void newProp(Property p)
{
props.add(p);
}
I have actively been seeking help in my seminar with this problem and I can't seem to find a solution, any advice would be very much appreciated!
In processProperty you are instantiating a new Organize object. Therefore, each Property (which you create for each row) is ending up in a different ArrayList (as the first element).
One solution would be to instantiate one Organize object before you start your loop and then pass this into your processProperty method as a parameter.
When one line in your text file is an empty String, your while-loop will break.
This is the right way to implement the loop:
String line = "";
while ((line = reader.readLine()) != null) {
// your code here
}
In processProperty you are instantiating a new Organize object. Therefore, each Property (which you create for each row) is ending up in a different ArrayList (as the first element).
One solution would be to instantiate one Organize object before you start your loop and then pass this into your processProperty method as a parameter.
String line = "";
while ((line = reader.readLine()) != null) {
// your code here
}