Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am getting hardware data from cmd using a process builder in java.
//get info from cmd
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("cmd.exe", "/c", "systeminfo ");
try {
Process process = processBuilder.start();
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
//write the output to the variables
String line;
//a loop which ensures all the data is read in
while ((line = reader.readLine()) != null) {
hardwareInfo.add(line);//hardwareInfo is an arraylist i currently save all this information to
}
This returns all the relevant information and more. my output looks like the following:
[, Host Name: LJDESKTOP, OS Name: Microsoft Windows 10 Education, OS Version: 10.0.18363 N/A Build 18363
etc...
I want to add some of these fields into an SQL database based on their names(e.g. Host Name: - yes, OS Name: - No). The SQL connection is set up I just need to find the best way to save these varibles so I can insert them straight into my database.
So how do I get rid of the Host Name: and still enter LJDESKTOP into my database and the same principle for the rest of the information I get from the cmd command.
I am also trying to consider efficiency, I want this to be as computationally "light" as possible but this isn't essential.
What I have tried so far:
I have tried splitting the string at the ":" for each varible and trimming. This gives me exactly the information I need but then I can't save it to individual variables. This is because the bit I trimmed is how I determine what my varibles are. (Could I potentially add the trim function to my setter?)
I have tried:
while ((line = reader.readLine()) != null) {
if (line.startsWith("Host Name:")) {
setHostname(line.replaceFirst("Host Name: ", ""));}
the if statements are repeated for each variable, however everytime this adds each variable to my array everytime it goes through the while loop.
You can try it like this:
...
final Map<String,String> inputValues = new HashMap<>();
//a loop which ensures all the data is read in
while ((line = reader.readLine()) != null) {
// Read each line as key and value into a the inputValues map
final String[] pieces = line.split(":",2); // only split at the first ':'!
// Was a ':' found, e.g. the string split into two pieces?
if ( pieces.length > 1 ) {
String key = pieces[0]; // e.g. "Host Name"
String value = pieces[1]; // e.g. " LJDESKTOP"
value = value.trim(); // remove leading/trailing whitespaces from value
inputValues.put(key,value); // Store key+value to map.
}
}
// Now we can access the input values by key, e.g.:
String hostName = inputValues.get("Host Name");
String osName = inputValues.get("OS Name");
// To do: Do something with the values above, e.g. send to DB...
Related
I need to execute .bat files in my java application. Suppose I have a text file with this sample content:
{
"id": 12,
"name": "test"
}
And in my .bat file, I have a command for outputing text file content. So this is my .bat file content:
#some other commands
more path\to\file.txt
And finally, this is my java code for executing this .bat file:
Process process = Runtime.getRuntime().exec("path\to\file.bat");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
List<String> outputs = new ArrayList<>();
while ((line = reader.readLine()) != null) {
outputs.add(line);
}
After executing this code, the outputs list has data something like this:
[...,
"{",
" "id": 12",",
" "name": "test",",
"}"
]
I means, this returns output line by line. But I want to have whole command output as one index of my list. In the other words, I want to have command by command instead of line by line output(every command has just one output).
Is this possible doing something like that?
Edit: I tried using ProcessBuilder also, but result was the same.
You claim
And in my .bat file, I have a command for outputing text file content.
and
I want to have command by command instead of line by line output(every command has just one output).
If I'm understanding this correctly, that means that you run your code only once (one "command") every time that you want to output a file. That is, you're only requiring that the outputs described are joined together in a single line, at which point you can put the lines in a list. This can be achieved like so:
Process process = Runtime.getRuntime().exec("path\to\file.bat");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();
List<String> outputs = new ArrayList<>();
//if desired, append prefix
//builder.append("File: {");
while ((line = reader.readLine()) != null) {
builder.append(line);
//if desired, append delimiter
//builder.append("\n");
}
//if desired, append suffix
//builder.append("}");
String concatenatedString = builder.toString();
Alternatively, in Java 8+, you can do the following (and even specify details of how lines are joined together):
Process process = Runtime.getRuntime().exec("path\to\file.bat");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String concatenatedString = reader.lines().collect(Collectors.joining(" "));
Naturally, I'm assuming that you're just using the example of reading files as a proxy for another where you must actually read a process' output. If all you require is a file read, a Process is not required to achieve this. Instead, you can get file contents as so:
String concatenatedString = "";
try (Stream<String> stream = Files.lines(Paths.get("path\to\text\file.txt"))) {
concatenatedString = stream.collect(Collectors.joining(" "));
}
//catch...
Now, if you actually want to join all text output together from many processes, but only have it as an aggregate (i.e. you can't join process outputs one by one, then store them), you're going to end up having to do the following:
Join all the strings:
This is easily doable using StringBuffer append or Collectors join as shown above.
Split them apart at the right places:
You will have to identify some marker of the separations between the relevant process outputs (for example, the text of the commands, or maybe the character at the end of the prompt). After identifying the marker(s), you'll have to write a regular expression or parser to separate out the relevant parts of your input, using methods like String substring or StringBuffer substring. If you use regular expressions to match the markers in your input to capturing groups, you can use region, start, and end to greatly simplify the process of splitting up your input.
As #Mofi and #kriegaex stated you should explain the use of batch files. I suppose that you already have them (batch files or some other executables) and you can not get rid of them but instead want to execute them and capture stdout of each execution into a single List or Map item.
Your current implementation appends each line into List:
while ((line = reader.readLine()) != null) {
outputs.add(line);
}
One solution is to use StringBuilder to concatenate stdout lines of each executable. After that each concatenated output is appended into Map. See this sample:
// Create Map for outpus.
Map<String, String> outputs = new HashMap<String, String>();
// Loop through batch files.
for (String bat : new String[] { "file12.bat", "file13.bat" }) {
// Execute batch.
Process process = Runtime.getRuntime().exec(bat);
// Open Reader...
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
// ... and read contents into StringBuilder.
StringBuilder contents = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
contents.append(line);
contents.append("\n"); // Append newline because reader.readLine() omits it.
}
// Close Reader.
reader.close();
// Add contents into Map.
outputs.put(bat, contents.toString());
}
After that you can verify Map contents for example like this:
for (String bat : outputs.keySet()) {
System.out.print("### output of ");
System.out.print(bat);
System.out.println(" ###");
System.out.println(outputs.get(bat));
}
It looks as if you do not want to perform a System.out.println() and instead collect all the output of a command and print it in bulk at the end of each command.
Well, then, write your own CommandResultCollector type where you initiate a StringBuffer and concatenate strings with proper line breaks as part of a single command execution and at the end of the command execution, convert it to a String and print the whole thing.
Alternatively, you can create an ArrayList and add all the Strings that are being printed as part of the command and iterate at the end of the execution to print them all at the end of every command execution.
I am sure there are better solutions that use the Heap memory intelligently. You can solve this problem in many ways, choose the simplest and least resource intensive one.
I would like to replace some items in a file, based on some regular expressions. In order to do that:
I read the file line per line
For every line, I check for the regular expression and I perform the replacement
Every line gets written in an array of strings
When all this is finished, I try to delete the file (in order to recreate it again with the replaced lines).
For some reason this does not work: it seems that Java keeps a handle on that file, even after the BufferedReader has been closed.
Does anybody have a solution for this (newbie) question?
Code excerpt:
Pattern oDatePattern = Pattern.compile("at \\d{2}:\\d{2}:\\d{2} "); // meaning: "at xx:xx:xx"
Pattern oTimePattern = Pattern.compile("Kernel time [0-9]*\\.?[0-9]+ User time: [0-9]*\\.?[0-9]+"); // "[0-9]*\.?[0-9]+" stands for any floating point number
Pattern oMemoryPattern = Pattern.compile("\\([0-9,A-F]*\\)"); // "[0-9,A-F]*" stands for any hexadecimal number
Matcher oDateMatcher;
Matcher oTimeMatcher;
Matcher oMemoryMatcher;
List<String> sLog_Content = new ArrayList<String>();
BufferedReader br = new BufferedReader(new FileReader(sLp_LogFile));
try {
String sLine = br.readLine();
while (sLine != null) {
System.out.println("ORIG : " + sLine);
oDateMatcher = oDatePattern.matcher(sLine);
sLine = oDateMatcher.replaceAll("at <timestamp> ");
oTimeMatcher = oTimePattern.matcher(sLine);
sLine = oTimeMatcher.replaceAll("Kernel time <Kernel_Time_usage> User time: <User_Time_usage>");
oMemoryMatcher = oMemoryPattern.matcher(sLine);
sLine = oMemoryMatcher.replaceAll("<Memory_Address>");
System.out.println("REPL : " + sLine);
sLog_Content.add(sLine);
sLine = br.readLine();
}
} finally {
br.close();
}
System.out.println("All lines are read and regex replaced, try to delete the file");
File tst_File = new File(sLp_LogFile);
if (tst_File.exists()) {
System.out.println(sLp_LogFile + " exists");
} else {
System.out.println(sLp_LogFile + " does not exist");
}
if (tst_File.delete()) {
System.out.println(sLp_LogFile + " is deleted");
} else {
System.out.println(sLp_LogFile + " is not deleted");
}
Output logs:
ORIG : Reading buffer 1 (0000000002ED0070) at 15:40:44 (index 125999, size 4410000 lines 126000, total lines read 126000)
REPL : Reading buffer 1 <Memory_Address> at <timestamp> (index 125999, size 4410000 lines 126000, total lines read 126000)
...
ORIG : Sending buffer 1 (0000000002ED0070) at 15:40:44 (index 125999, size 4410000, lines 126000, total lines sent 126000)
REPL : Sending buffer 1 <Memory_Address> at <timestamp> (index 125999, size 4410000, lines 126000, total lines sent 126000)
...
ORIG : Kernel time 0.2808 User time: 0.312
REPL : Kernel time <Kernel_Time_usage> User time: <User_Time_usage>
...
All lines are read and regex replaced, try to delete the file
D:\Logfile_lp.log exists
D:\Logfile_lp.log is not deleted
One possible explanation is that your application has the file open somewhere else.
Or it could be another application that has the file open.
Or maybe the application / user has permission to read the file but not to delete it.
I concur with the suggestion of using Files.delete ..
I see no issues in your code.
Seemingly closing the BufferReader ensure the file is closed. (cf this response).
Maybe you can give a try to Files.delete cf this response.
It will give more information about the deletion fail by throwing different exceptions.
Good afternoon,
I would like to thank you all for having searched for a solution of this problem. Unfortunately the problem is not Java based: the file I'm trying to write to is created by a redirection cmd /c <program>.exe >> <output>.log, and it seems that Windows has not fully flushed the output buffer towards the output file, creating the problem.
I am currently using following (very dirty) work-around for this issue:
boolean bFile_can_be_opened = false;
while (!bFile_can_be_opened) {
try {
fwLog2 = new FileWriter(sLp_LogFile, true);
bFile_can_be_opened = true;
}
catch (Exception e)
{}
}
Further information on this issue can be found under the following new StackOverflow question: How to release a file, locked by the application, in Java
I'm a beginner, I do not know as much things as you. But if I am right you should save your changes first a temp file. Afterwards you will read again the temp file and later you'll write to your real file. I hope my comment will help you.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have a code that is running on NodeJs. We would like to change the technology (to java).
The problem is we have some existing passwords, and I am not sure how to I copy the encryption logic to java.
So, one of the possible solutions is to run the encryption logic in javascript (e.g. command line, embbeded in the java, etc) and get the result back.
The question is - how do I do that?
The nodejs code goes like this:
crypto = require('crypto');
this.salt = this.makeSalt();
encryptPassword: function(password) {
var salt = new Buffer(this.salt, 'base64');
return crypto.pbkdf2Sync(password, salt, iterations, keylen).toString('base64');
crypto.randomBytes(..)
}
makeSalt: function() {
return crypto.randomBytes(numOfBytes).toString('base64');
},
UPDATE:
Following the suggestions here, I added the full code. If the right way of doing it is by transforming the javascript code to java code, can you please help me translated the above code?
You should not do this, if you want random bytes in Java do this. You should be able to replicate the encryption logic in Java.
byte[] b = new byte[20];
new Random().nextBytes(b);
Almost all of the Node.js crypto functions are generic, and should have their own Java counterparts or 3rd party libraries.
Update
If you must run your node code via java you can add this method
public static String runCommand(String command) {
String output = "";
try {
String line;
Process process = Runtime.getRuntime().exec( command );
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()) );
while ((line = reader.readLine()) != null) {
output += line;
}
reader.close();
} catch (Exception exception) {
// ...
}
return output;
}
and run it like this
String encryptedPassword = runCommand("node myEncryption.js --password=1234");
I've got two problems with the android app I'm writing.
I'm reading out the local arp table from /proc/net/arp and save ip and corresponding mac address in a hash map. See my function. It's working properly.
/**
* Extract and save ip and corresponding MAC address from arp table in HashMap
*/
public Map<String, String> createArpMap() throws IOException {
checkMapARP.clear();
BufferedReader localBufferdReader = new BufferedReader(new FileReader(new File("/proc/net/arp")));
String line = "";
while ((line = localBufferdReader.readLine()) != null) {
String[] ipmac = line.split("[ ]+");
if (!ipmac[0].matches("IP")) {
String ip = ipmac[0];
String mac = ipmac[3];
if (!checkMapARP.containsKey(ip)) {
checkMapARP.put(ip, mac);
}
}
}
return Collections.unmodifiableMap(checkMapARP);
}
First problem:
I'm also using a broadcast receiver. When my app receives the State WifiManager.NETWORK_STATE_CHANGED_ACTION i check if the connection to the gateway is established. If true i call my function to read the arp table. But in this stage the system has not yet builded up the arp table. Sometimes when i receive the connection state the arp table is sill empty.
Anyone got an idea to solve this?
Second problem:
I want to save the ip and mac address of the gateway in a persistent way. Right now i'm using Shared Preferences for this. Maybe it's better to write to an internal storage?
Any tips?
For the first problem you could start a new thread that runs that method after sleeping for a set amount of time or until it has some entries (Make a Runnable with a mailbox to get the Map) - unless you need to use the map directly, then I think the only way is to wait for the entries. For example (if you need to use the map directly):
public Map<String, String> createArpMap() throws IOException {
checkMapARP.clear();
BufferedReader localBufferdReader = new BufferedReader(new FileReader(new File("/proc/net/arp")));
String line = "";
while ((line = localBufferdReader.readLine()) == null) {
localBufferdReader.close();
Thread.sleep(1000);
localBufferdReader = new BufferedReader(new FileReader(new File("/proc/net/arp")));
}
do {
String[] ipmac = line.split("[ ]+");
if (!ipmac[0].matches("IP")) {
String ip = ipmac[0];
String mac = ipmac[3];
if (!checkMapARP.containsKey(ip)) {
checkMapARP.put(ip, mac);
}
}
} while ((line = localBufferdReader.readLine()) != null);
return Collections.unmodifiableMap(checkMapARP);
}
In one commend , I'm trying to send data to System.out like this:
And in another command I'm trying to get this data from System.in.
It's strange because, it works once of many tries. I can try to run it 10 times and it's still inReader.ready() == false, and when I run it for example 11th time , it works.
Why ? How can I fix this? How to make it work everytime ?
Thanks, in advance !
You can't read your InputStream that way, since the data may not have been arrived at the second process yet. You can either read character by character, with something like:
InputStreamReader inReader = new InputStreamReader(System.in);
int data = inReader.read();
while (data != -1){
...
data = inReader.read();
}
or simple read the input line by line, using:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while ((String line = br.readLine()) != null) {
...
}
If your objective is to execute a shell command, don't use System.out but Runtime.getRuntime().exec(cmd) instead. Check out this question for more details.