I'm trying to store documents(doc,ppt,pdf,txt..etc) in MSSQL(server running in AWS). I'm working on the app module (android). I can get the files from the user but I'm not able to upload it to the database.
What I've done so far:
Tried to upload the file directly using setBinaryStream
Tried to upload the fileInputStream using setBinaryStream
No blob type can be declared in this database column
Update
Code Requested:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.sm_attachments:
FilePickerDialog filePickerDialog = new FilePickerDialog(SendMailToCustomers.this,properties);
filePickerDialog.setTitle("Select Files");
filePickerDialog.show();
filePickerDialog.setDialogSelectionListener(new DialogSelectionListener() {
#Override
public void onSelectedFilePaths(String[] files) {
for (String file : files) {
Uri uri = Uri.fromFile(new File(file));
try {
File file1 = new File(uri.getPath());
//InputStream inputStream = new FileInputStream(new File(uri.getPath()));
byte[] bytesArray = null;
bytesArray = new byte[(int) file1.length()];
FileInputStream fileInputStream = new FileInputStream(file1);
fileInputStream.read(bytesArray);
String sql = "INSERT INTO Storedata (FileName,MyFile) values (?,?)";
PreparedStatement statement = con.prepareStatement(sql);
statement.setString(1,"myNewFile");
//statement.setBinaryStream(2, /*inputStream*/fileInputStream,fileInputStream.available());
statement.setBytes(2, /*inputStream*/bytesArray);
int row = statement.executeUpdate();
if(row>0){
Toast.makeText(SendMailToCustomers.this, "The File was inserted Successfully", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onSelectedFilePaths: Inserted File Successfully");
}
else{
Toast.makeText(SendMailToCustomers.this, "Failed To Insert File", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onSelectedFilePaths: Failed To Insert File");
}
} catch (Exception e) {
Log.d(TAG, "onSelectedFilePaths: "+"Exception - "+e.getMessage()+"\n");
e.printStackTrace();
}
break;
The String[] files - are the selected files(Uri) for upload.
Next is the picture of my SQL Database:
MyFile is varbinary(MAX)
Upon doing this : statement.setBytes(2, /inputStream/bytesArray);
I get the below result. But this is around 433984 byte length i.e. bytes read for one file. How should i go about this?
The BULK IMPORT would not natively be able to do this however if you are on SQL2005 or greater you can use SSIS. The first step would be to perform an Exectute Process Task and use a zip utility to unzip the file. The second step is to use the SSIS Bulk Insert task to push the data into SQL Server.
Related
Good day everyone! I am trying to create a desktop application using java swing wherein the user can upload pdf files to the mysql database. I already did the upload part in the application, but I'm having trouble on making a download button in the application. The function of the download button is to retrieve the pdf file in the mysql database and then download it in the user's computer.
here's what I found in inserting pdf file from https://www.java-tips.org/other-api-tips-100035/69-jdbc/845-how-to-storeretrieve-pdf-document-tofrom-sqlserver.html
The above link has already a function in getting pdf data, but I can't seem to understand how to implement it in my download button.
public void upload(Connection conn,String filename) {
int len;
String query;
PreparedStatement pstmt;
try {
File file = new File(filename);
FileInputStream fis = new FileInputStream(file);
len = (int)file.length();
query = ("insert into fileStorage VALUES(?,?,?)");
pstmt = conn.prepareStatement(query);
pstmt.setString(1,file.getName());
pstmt.setInt(2, len);
//method to insert a stream of bytes
pstmt.setBinaryStream(3, fis, len);
pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
}
What I'm having a trouble is making a function for my download button. how do I retrieve the file from database and download it at the same time after clicking the download button.
Yeah so unfortunately I don't know your table format however we should be able to create a prepared statement that gets the file raw bytes from the database. The following will get the byte array from the database and then create a new file, if necessary, from the raw bytes.
Change fileName to the proper name of the column for the file name.
Change fileContent to the name of the column for the byte array.
Make sure fileContent is a varbinary type.
Replace null in my reference to download(Connection, String) with a legitimate non-null Connection reference.
public static void main(String[] args) {
try {
byte[] download = download(null, "test");
Path output = Paths.get("my", "output", "file.pdf");
Files.write(output, download, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);
} catch (IOException | SQLException e) {
throw new RuntimeException("Uh oh something went wrong!", e);
}
}
static byte[] download(Connection connection, String fileName) throws SQLException {
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM fileStore WHERE fileName = ?")) {
statement.setString(1, fileName);
try (ResultSet results = statement.getResultSet()) {
if (results.next()) {
return results.getBytes("fileContent");
}
}
}
throw new IllegalStateException("No file can be found for this name.");
}
Below is the working method to Import and Export SQLite database. Its Working just fine in all android versions excluding Android Pie. When I am trying to import in Android pie, it shows successful toast but database is not being restored. Can anybody help me workaround in Android Pie(API 28).
private void importDB() {
try {
File sd = Environment.getExternalStorageDirectory();
File cur_db_pat = new File(this.getDatabasePath(DATABASE_NAME).getAbsolutePath());
if (sd.canWrite()) {
String backupDBPath = bac_dir_nam +"/" + DATABASE_NAME;
File currentDB = new File(sd, backupDBPath);
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(cur_db_pat).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(getBaseContext(), cur_db_pat.toString(),
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG)
.show();
}
}
private void exportDB() {
try {
File sd = Environment.getExternalStorageDirectory();
File cur_db_pat = new File(this.getDatabasePath(DATABASE_NAME).getAbsolutePath());
if (sd.canWrite()) {
String backupDBPath = bac_dir_nam+"/" + DATABASE_NAME;
File backupDB = new File(sd, backupDBPath);
FileChannel src = new FileInputStream(cur_db_pat).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(getBaseContext(), backupDB.toString(),
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG)
.show();
}
}
I don't have much experience with file system. So an example would help a lot.
In Android Pie+ SQLite has changed to default to using the generally more efficient Write Ahead Logging (WAL) instead of Journal mode.
As such there will be two files with the same name as the database but suffixed with -shm (shared memory file) and -wal (write ahead log) and their presence is what I believe causes the issue(s).
Temporary Files Used By SQLite (see 2.2 and 2.3)
One fix would be to disable Write Ahead Logging using use the SQliteDatabase disableWriteAheadLogging method and the previous method would work as before but with the less efficient journal mode.
(if using a subclass of SQliteOpenHelper then override the onConfigure method to invoke this method. ) disableWriteAheadLogging.
Another fix is to delete these two files when restoring. To avoid the potential for corruption you have to ensure that the database was adequately checkpointed before making the backup. see PRAGMA checkpoint;
The following is a snippet that deletes these two files when restoring (noting that the backup is assumed to have been taken with adequate checkpointing):-
// Added for Android 9+ to delete shm and wal file if they exist
File dbshm = new File(dbfile.getPath() + "-shm");
File dbwal = new File(dbfile.getPath()+ "-wal");
if (dbshm.exists()) {
dbshm.delete();
}
if (dbwal.exists()) {
dbwal.delete();
}
Another fix would be to additionally backup and subsequently restore the -shm and -wal files.
You may also wish considering the potential benefits of renaming the original files when importing/restoring, checking the new files after they have been copied (e.g. using PRAGMA integrity_check;) if the results indicat no issues then delete the renamed original files, otherwise delete the imported files and rename the original files to their original name, indicating that the import failed.
In your class for Db WorkHelper ovverride onOpen() method and set disableWriteAheadLogging then call onOpen() standard, if version of android sdk 28 , sure then old version remain old modality.
#Override
public void onOpen(SQLiteDatabase database) {
super.onOpen(database);
if(Build.VERSION.SDK_INT >= 28)
{
database.disableWriteAheadLogging();
}
}
In my case WORK perfect.
Unlike what the other commenters have suggested, you can't rely on the database consisting of a single file after write-ahead logging is disabled, and you can't assume that the -shl and -wal filenames remain correct. This is all an implementation detail of sqlite3 / Android and therefore subject to change at any time (just like the old code broke).
One way of doing this that I expect to continue working is to use sqlite3's .dump command to convert the database into SQL that can later be executed in order to recreate the database.
I haven't tested the following, but expect that something similar to it should work:
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
// Untested:
private byte[] exportDatabase(SQLiteDatabase database) throws IOException {
Process process = new ProcessBuilder()
.command("/system/bin/sqlite3", database.getPath(), ".dump")
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.start();
try (InputStream inputStream = process.getInputStream()) {
// [read the full contents of inputStream and save them somewhere]
return ByteStreams.toByteArray(inputStream);
} finally {
waitForProcess(process);
}
}
private void importDatabase(String databasePath, InputStream backedUpData) throws IOException {
// restore the database:
Process process = new ProcessBuilder()
.command("/system/bin/sqlite3", databasePath)
.redirectInput(ProcessBuilder.Redirect.PIPE)
.start();
try (OutputStream outputStream = process.getOutputStream()) {
// now write the backed-up contents back to outputStream
ByteStreams.copy(backedUpData, outputStream);
}
waitForProcess(process);
}
private static void waitForProcess(Process process) {
try {
process.waitFor();
} catch (InterruptedException e) {
// ignore interruption, restore interrupt flag
Thread.currentThread().interrupt();
}
}
Obviously, you'll have to ensure that:
The database that you're backing up isn't currently open.
The database that you're restoring doesn't already exist.
How are you?
Within a project that I am doing I need to obtain an image of the computer and save it in a database, for this I used the field input type = file.
To save it I use the following function:
public boolean guardarfoto(int idProducto, String imagen) {
FileInputStream fis = null;
try {
File file = new File("C:\\" + imagen);
fis = new FileInputStream(file);
cpsql.conectar();
connection = ConexionPgSQL.getCn();
PreparedStatement pstm = connection.prepareStatement("UPDATE productos SET imagen_producto = ?, nombre_imagen = ? where id_producto = ?");
pstm.setBinaryStream(1, fis, (int) file.length());
pstm.setString(2, imagen);
pstm.setInt(3, idProducto);
pstm.execute();
System.out.println("Agregando imagen: " + pstm.toString());
pstm.close();
return true;
} catch (FileNotFoundException | SQLException e) {
Logger.getLogger(ControladorProducto.class.getName()).
log(Level.SEVERE, null, e);
}
return false;
}
My problem is that this function only allows me to save an image that is inside the specified directory, in this case C: \, because if in the function I replaced the File file = new File ("C: \\" + image); by File file = new File (image); it seems to try to look for the route internally in the project, and not in the directory of the computer, and would therefore like to replace that static directory with a dynamic one so as not to limit the client to having to move the image to the specified route so that Do not mark error when saving.
For this, I am working on a Web project using NetBeans 8.0.2, JSPs and Servlets.
In Java JSP, I'm using input stream and BLOB datatype to write any type of file into the database. I want to retrieve the BLOB file. How should I go about retrieving it? I tried using select statement and got this (material column).
Using a ResultSet, you can retrieve a java.sql.Blob instance:
Blob blob = resultSet.getBlob("MATERIAL");
Then you can open an input stream:
InputStream input = blob.getBinaryStream();
And write it to a file as described in Is it possible to create a File object from InputStream
Getting the Blob from the table:
try (ResultSet rs = statement.executeQuery(query)) {
if(rs.next()) {
fileBlob = rs.getBlob(1);
}
}
Saving the contents of the Blob into a new file:
try (InputStream ipStream = fileBlob.getBinaryStream(1, fileBlob.length());
OutputStream opStream = new FileOutputStream(new File("path/to/file"))) {
int c;
while ((c = ipStream.read()) > -1) {
opStream.write(c);
}
}
i have a stupid question here i'm implementing upload button with vaadin and i want the users to upload only compressed files (.zip,.rar..), imake a search but i didn't find something useful :
so i tried to do this , i know it's not good solution because the user already uploaded the selected file :
#Override
public OutputStream receiveUpload(String filename, String mimeType) {
// Create upload stream
FileOutputStream fos = null; // Stream to write to
String fileName ;
String userHome = System.getProperty( "user.home" );
try {
// Open the file for writing.
file = new File(userHome+"/kopiMap/runtime/uploads/report/" + filename);
fileName= file.getName();
//Here i will get file extension
fos = new FileOutputStream(file);
} catch (final java.io.FileNotFoundException e) {
Notification.show(
"Could not open file<br/>", e.getMessage(),
Notification.TYPE_ERROR_MESSAGE);
return null;
}
return fos; // Return the output stream to write to
}
So how to do it before uploading
you can check the mimeType and if it is application/zip
#Override
public OutputStream receiveUpload(String filename, String mimeType) {
// Create upload stream
if(mimeType.equals("application/zip"))
//Here you can restrict
You can add this and it will work (all done by HTML 5 and most browser support now accept attribute) - this is example for .csv files:
upload.setButtonCaption("Import");
JavaScript.getCurrent().execute("document.getElementsByClassName('gwt-FileUpload')[0].setAttribute('accept', '.csv')");