How to generate fixed length random number without conflict?
From a comment, it seems that you are generating group codes for your own application.
For the purposes and scale of your app, 5-character codes may be appropriate. But there are several points you should know:
- Random number generators are not designed to generate unique numbers. You can generate a random code as you're doing now, but you should check that code for uniqueness (e.g., check it against a table that stores group codes already generated) before you treat that code as unique.
- If users are expected to type in a group code, you should include a way to check whether a group code is valid, to avoid users accidentally joining a different group than intended. This is often done by adding a so-called "checksum digit" to the end of the group code. See also this answer.
- It seems that you're trying to generate codes that should be hard to guess. In that case,
Math.random()
is far from suitable (as isjava.util.Random
) — especially because the group codes are so short. Use a secure random generator instead, such asjava.security.SecureRandom
(fortunately for you, its security issues were addressed in Android 4.4, which, as I can tell from a comment of yours, is the minimum Android version your application supports; see also this question). Also, if possible, make group codes longer, such as 8 or 12 characters long.
For more information, see Unique Random Identifiers.
Also, there is another concern. There is a serious security issue if the 5-character group code is the only thing that grants access to that group. Ideally, there should be other forms of authorization, such as allowing only logged-in users or certain logged-in users—
- to access the group via that group code, or
- to accept invitations to join the group via that group code (e.g., in Google Classroom, the
PERMISSION_DENIED
error code can be raised when a user tries to accept an invitation to join a class).
Random Number generator in a range and then print length of the sequence
Consider using a while-loop:
import java.util.Random;
class Sequence {
public static void main(String[] args) {
Random r = new Random();
int count = 0;
int num = -1;
System.out.println("The sequence is:");
while (num != 0) {
num = r.nextInt(10);
System.out.print(num + " ");
count++;
}
System.out.printf("%nThe length of the sequence is: %d%n", count);
}
}
Example Output:
The sequence is:
3 9 3 9 4 0
The length of the sequence is: 6
Alternatively if you need to store the sequence in a collection:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
class Sequence {
public static void main(String[] args) {
Random r = new Random();
List<Integer> result = new ArrayList<>();
int num = -1;
while (num != 0) {
num = r.nextInt(10);
result.add(num);
}
System.out.printf("The sequence is: %s%n", result);
System.out.printf("The length of the sequence is: %d%n", result.size());
}
}
Problem to generate random unique numbers from fixed population length
You should generate the random numbers beforehand, so you are certain they are not repeated.
An easy way of doing this is to obtain a list of integers and then shuffle it.
For example:
// Obtain a list of integers from 0 to the size of population - 1
final List<Integer> integers = Stream.iterate(0, n -> n + 1)
.limit(population)
.collect(Collectors.toList());
// integers will have have [0, 1, 2, .... n]
// Then shuffle them
Collections.shuffle(integers);
// integers will have have something like [3, 66, 44, .... n] randomly
Check https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#shuffle-java.util.List-java.util.Random-
Generate a random integer with a specified number of digits Java
private long generateRandomNumber(int n) {
long min = (long) Math.pow(10, n - 1);
return ThreadLocalRandom.current().nextLong(min, min * 10);
}
nextLong
produces random numbers between lower bound inclusive and upper bound exclusive so calling it with parameters (1_000, 10_000)
for example results in numbers 1000 to 9999.
Old Random
did not get those nice new features unfortunately. But there is basically no reason to continue to use it anyways.
Simple export and import of a SQLite database on Android
I use this code in the SQLiteOpenHelper
in one of my applications to import a database file.
EDIT: I pasted my FileUtils.copyFile()
method into the question.
SQLiteOpenHelper
public static String DB_FILEPATH = "/data/data/{package_name}/databases/database.db";
/**
* Copies the database file at the specified location over the current
* internal application database.
* */
public boolean importDatabase(String dbPath) throws IOException {
// Close the SQLiteOpenHelper so it will commit the created empty
// database to internal storage.
close();
File newDb = new File(dbPath);
File oldDb = new File(DB_FILEPATH);
if (newDb.exists()) {
FileUtils.copyFile(new FileInputStream(newDb), new FileOutputStream(oldDb));
// Access the copied database so SQLiteHelper will cache it and mark
// it as created.
getWritableDatabase().close();
return true;
}
return false;
}
FileUtils
public class FileUtils {
/**
* Creates the specified <code>toFile</code> as a byte for byte copy of the
* <code>fromFile</code>. If <code>toFile</code> already exists, then it
* will be replaced with a copy of <code>fromFile</code>. The name and path
* of <code>toFile</code> will be that of <code>toFile</code>.<br/>
* <br/>
* <i> Note: <code>fromFile</code> and <code>toFile</code> will be closed by
* this function.</i>
*
* @param fromFile
* - FileInputStream for the file to copy from.
* @param toFile
* - FileInputStream for the file to copy to.
*/
public static void copyFile(FileInputStream fromFile, FileOutputStream toFile) throws IOException {
FileChannel fromChannel = null;
FileChannel toChannel = null;
try {
fromChannel = fromFile.getChannel();
toChannel = toFile.getChannel();
fromChannel.transferTo(0, fromChannel.size(), toChannel);
} finally {
try {
if (fromChannel != null) {
fromChannel.close();
}
} finally {
if (toChannel != null) {
toChannel.close();
}
}
}
}
}
Don't forget to delete the old database file if necessary.
Export and import SQLite database
FileNotFoundException is likely due to the directory teste not existing, perhaps due to permissions.
Using :-
private void backupDatabase () throws IOException {
String inFileName = "/data/data/com.gnd.example/databases/dados.db";
File dbFile = new File (inFileName);
FileInputStream fis = new FileInputStream (dbFile);
String outFileName = Environment.getExternalStorageDirectory () + "/ example / backup / data.db";
//<<<<<<<<<<< CODE ADDED >>>>>>>>>>
File os = new File(outFileName);
if (!os.getParentFile().exists()) {
os.getParentFile().mkdirs();
}
//<<<<<<<<<< END Of ADDED CODE >>>>>>>>>>
OutputStream output = new FileOutputStream(os); //<<<<<<<<<< CHANGED
byte [] buffer = new byte [1024];
int length;
while ((length = fis.read (buffer))> 0) {
output.write (buffer, 0, length);
}
output.flush ();
output.close ();
fis.close ();
}
will create the directories if they do not exist (assuming permissions are correct)
Working Example :-
The following is a working app
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="aso.so56843045backup">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
- Note the
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
(for earlier devices)
ExternalStoragePermissions.java
class ExternalStoragePermissions {
public int API_VERSION = Build.VERSION.SDK_INT;
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
//Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static final String THISCLASS = ExternalStoragePermissions.class.getSimpleName();
private static final String LOGTAG = "SW_ESP";
public ExternalStoragePermissions() {}
// Note call this method
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
}
- If permissions not given then the directories cannot be created resulting in FileNotFoundException.
DBHelper.java
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "dados.db";
public static final int DBVERSION = 1;
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
- A Very basic empty database (exception android_metadata table), enough to check backup.
MainActivity.java
public class MainActivity extends AppCompatActivity {
DBHelper mDBHlpr;
Button mBackup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBackup = this.findViewById(R.id.backup);
mBackup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDBHlpr.close();
try {
backupDatabase();
} catch (IOException e) {
e.printStackTrace();
}
}
});
ExternalStoragePermissions.verifyStoragePermissions(this);
mDBHlpr = new DBHelper(this);
}
private void backupDatabase () throws IOException {
FileInputStream fis = new FileInputStream (this.getDatabasePath("dados.db").getPath());
String outFileName = Environment.getExternalStorageDirectory () + "/example/backup/" + String.valueOf(System.currentTimeMillis()) + "data.db";
Log.d("OSFILEPATH",outFileName);
File os = new File(outFileName);
if (!os.getParentFile().exists()) {
os.getParentFile().mkdirs();
}
OutputStream output = new FileOutputStream(os);
byte [] buffer = new byte [1024];
int length;
while ((length = fis.read (buffer))> 0) {
output.write (buffer, 0, length);
}
output.flush ();
output.close ();
fis.close ();
}
}
Notes
When first run after install permission will be requested for later devices (click allow).
Backup has been named with a timestamp so multiple backups can exist.
Database is closed, (this should cope with Android Pie+ wehere default is WAL mode, the close should empty (commit the changes) the -wal and -shm files, thus negating the need to backup the additional files).
Result
Related Topics
Org.Hibernate.Annotationexception: @Onetoone or @Manytoone on <Entity> References an Unknown Entity
Method Does Not Override Method from Its Superclass . Android Fragment
How to Check Heap Usage of a Running Jvm from the Command Line
Spring Boot API Call With Multiple @Requestparam
Java.Io.Filenotfoundexception: the System Cannot Find the File Specified
Refactor Multiple If' Statements in Java-8
How to Get the Path of Src/Test/Resources Directory in Junit
Java Program to Find Palindrome Numbers in Given Range
How to Save a File Downloaded With Httpclient into a Specific Folder
How to Test If Json Collection Object Is Empty in Java
How to Test Class Which Implements Runnable With Junit
Jackson Deserialization Issue for Zoneddatetime
Codility Tape Equilibrium Getting Zero on Some Cases
Array Pairwise Matching in Java Give Error Also Store Data Between Two Similar Element
Spring JPA Repository: Prevent Update on Save
I Get a Status 200 When Connecting to the Websocket, But It Is an Error