I'm strugging to rename files with content to SMB using com.hierynomus.smbj.
Files are generated with content, but after renaming content is gone.
Following implementation renames files:
public void rename(String pathFrom, String pathTo) {
pathFrom = formatPath(pathFrom);
pathTo = formatPath(pathTo);
Set<SMB2ShareAccess> shareAccessSet = new HashSet<>();
shareAccessSet.add(SMB2ShareAccess.FILE_SHARE_READ);
shareAccessSet.add(SMB2ShareAccess.FILE_SHARE_WRITE);
shareAccessSet.add(SMB2ShareAccess.FILE_SHARE_DELETE);
Set<FileAttributes> fileAttributes = new HashSet<>();
fileAttributes.add(FileAttributes.FILE_ATTRIBUTE_NORMAL);
Set<SMB2CreateOptions> createOptions = new HashSet<>();
SMB2CreateDisposition smb2CreateDisposition = SMB2CreateDisposition.FILE_OVERWRITE_IF;
if (isFolder(pathFrom)) {
createOptions.add(SMB2CreateOptions.FILE_DIRECTORY_FILE);
smb2CreateDisposition = SMB2CreateDisposition.FILE_OPEN_IF;
}
else if (isFile(pathFrom)) {
createOptions.add(SMB2CreateOptions.FILE_NON_DIRECTORY_FILE);
}
else {
throw new IllegalArgumentException("Path '" + pathFrom + "' can't be resolved to file nor directory");
}
try (DiskEntry file = this.smbShare.open(pathFrom, of(AccessMask.MAXIMUM_ALLOWED), fileAttributes, shareAccessSet,
smb2CreateDisposition, createOptions)) {
file.rename(pathTo, true);
}
}
Maybe I messed up the attributes and options in smbShare.open-function?
Hm.. I messed up with properties of SMB2CreateDisposition.
The solution: smb2CreateDisposition = SMB2CreateDisposition.FILE_OPEN_IF;
instead of smb2CreateDisposition = SMB2CreateDisposition.FILE_OVERWRITE_IF;
The former opens (1.) or creates (2.) the file in question.
The latter overwrites the existing file.
Related
I want to implement this functionality;
A Button when pressed will install .xapk file from local storage with the following path.
String _apkFilePath = '/storage/emulated/0/Download/filename.xapk';
Duplicate of: I am making an .XAPK installer application in flutter. with open_file package I can open normal .apk installation dialogue but how can I install .XAPK
If you're still trying to install an .xapk file, I'm sharing a piece of code that helped me. I'm using the packages:
archive (for all the extraction as zip logic)
device_apps (to open the Settings app in case you don't have the required permissions)
open_filex (to open the apk file with the Android intent)
package_archive_info (to get the information from the .apk package)
path_provider (to get Directories and paths)
permission_handler (to ask for permissions to install)
and file_picker since I initiate the method with a picked file using that package.
abstract class XapkInstaller {
static install({required PlatformFile file}) async {
late List<FileSystemEntity> allFiles, apkFiles;
late PackageArchiveInfo appInfo;
late String appPackageName;
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
String appName = file.path.toString().split("/").last.replaceAll(".apklis", "");
String zipFilePath = "${tempDir.path.replaceAll('/$appName.apklis', '')}/$appName.zip";
// this function convert xapk in zip file and moves in appname_zip directory
_moveFile(File(file.path.toString()), zipFilePath);
final bytes = File(zipFilePath).readAsBytesSync();
final archive = ZipDecoder().decodeBytes(bytes);
// Extract the contents of the Zip archive to disk app cache.
for (final file in archive) {
final String filename = file.name;
if (file.isFile) {
final data = file.content as List<int>;
File("${tempDir.path}/$appName/$filename")
..createSync(recursive: true)
..writeAsBytesSync(data);
} else {
Directory(tempPath).create(recursive: true);
}
}
final Directory myDir = Directory("${tempDir.path}/$appName");
allFiles = myDir.listSync(recursive: true, followLinks: true);
apkFiles = allFiles.where((element) => element.path.endsWith('.apk')).toList();
for (int x = 0; x < apkFiles.length; x++) {
final String filePath = apkFiles[x].path;
try {
appInfo = await PackageArchiveInfo.fromPath(filePath);
appPackageName = appInfo.packageName;
} catch (e) {
appInfo = PackageArchiveInfo(appName: "", packageName: "", version: "", buildNumber: "");
}
if (appInfo.appName.isNotEmpty) {
try {
// moving obb file to android/obb folder
_moveObbToAndroidDir(allFiles, appPackageName);
// showing popup to install app
if (await Permission.requestInstallPackages.request().isGranted) {
await OpenFilex.open(filePath);
} else {
DeviceApps.openAppSettings(appInfo.packageName);
}
} catch (e) {
//catch error in installing
}
}
}
// clearing cache file after installing xapk
Future.delayed(const Duration(seconds: 180), () {
tempDir.deleteSync(recursive: true);
tempDir.create();
});
}
static _moveObbToAndroidDir(List<FileSystemEntity> allFiles, String appPackageName) async {
for (int x = 0; x < allFiles.length; x++) {
final fileExtension = allFiles[x].path.split("/").last.split(".").last;
if (fileExtension == "obb") {
String filepath = allFiles[x].path;
String obbFileName = filepath.split("/").last.split(".").first;
String obbDirPath = "/Android/obb/$appPackageName";
// creating the directory inside android/obb folder to place obb files
if (!Directory(obbDirPath).existsSync()) {
Directory(obbDirPath).createSync();
}
// rename path should also contains filename i.e. whole path with filename and extension
final String renamePath = "$obbDirPath/$obbFileName.obb";
try {
// syncronus copying
File(filepath).copySync(renamePath);
} on FileSystemException {
// in case of exception copying asyncronushly
await File(filepath).copy(renamePath);
}
}
}
}
static Future<File> _moveFile(File sourceFile, String newPath) async {
try {
// prefer using rename as it is probably faster
return await sourceFile.rename(newPath);
} on FileSystemException catch (e) {
// if rename fails, copy the source file and then delete it
final newFile = await sourceFile.copy(newPath);
await sourceFile.delete();
return newFile;
}
}
}
I've tried it and it works, so remember to update the permissions on the AndroidManifest file and you're all set.
I have cloned a directory in my container using Jgit code for reference
public UpdateProjectDto pushIntoGit(String id, String Name, GitDTO gitDTO, File archiveFolder, boolean upgradeProject) {
log.info("Pushing {} in git repo {} ", Name, gitDTO.getRepoUrl());
final GitConfiguration gitConfiguration = findConfigurationByUrl(gitDTO.getRepoUrl());
String latestCommitId;
File Dir = null;
File destination = null;
UpdateProjectDto updateProjectDto = new UpdateProjectDto();
final UsernamePasswordCredentialsProvider usernamePasswordCredentialsProvider = new UsernamePasswordCredentialsProvider(gitConfiguration.getUserName(), gitConfiguration.getPassword());
final CloneCommand cloneCommand = Git.cloneRepository();
cloneCommand.setURI(gitDTO.getRepoUrl());
cloneCommand.setCredentialsProvider(usernamePasswordCredentialsProvider);
try {
final Git gitRepo = cloneCommand.call();
final String repoName = gitUtils.getRepoName(gitDTO.getRepoUrl());
if (gitDTO.getLastCommitId().equals(getLastCommitId(gitRepo))) {
removeGitFolder(archiveFolder);
Dir = new File(String.format("temp/%s", Name));
Dir.mkdir();
FileUtils.copyDirectory(archiveFolder, Dir);
FileUtils.deleteDirectory(archiveFolder);
destination = new File(gitRepo.getRepository().getDirectory().getParent());
FileUtils.copyDirectory(Dir.getParentFile(), destination);
FileUtils.deleteDirectory(Dir);
gitRepo.add().addFilepattern(".").call();
gitRepo.commit().setMessage(String.format(" %s pushed into git", Name)).call();
final PushCommand push = gitRepo.push();
push.setRemote(Constants.ORIGIN);
push.add(Constants.MASTER);
push.setCredentialsProvider(usernamePasswordCredentialsProvider);
push.call();
log.info("Git Push successful for {} in git repo {} ", Name, gitDTO.getRepoUrl());
latestCommitId = getLastCommitId(gitRepo);
if (!upgradeProject) {
updateProjectDto = workspacesServiceClient.addLatestCommitIdToProject(gitDTO.getProjectId(), latestCommitId, Collections.singletonList(id), ProjectEventType.CREATED);
} else {
updateProjectDto.setCommitId(latestCommitId);
updateProjectDto.setUserName(gitDTO.getUsername());
}
log.info(String.format("UpdateProjectDto: %s, repository name: %s", updateProjectDto.toString(), repoName));
final File projectDirectoryForUser = gitUtils.getProjectDirectoryFromRepoName(updateProjectDto.getUserName(), repoName);
if (!projectDirectoryForUser.exists()) {
FileUtils.deleteDirectory(new File(repoName));
throw new internalServerError(String.format(ExceptionMessage.GIT_DIRECTORY_NOT_FOUND, repoName));
}
updateGitFolder(projectDirectoryForUser, gitConfiguration);
FileUtils.deleteDirectory(destination);
gitRepo.getRepository().close();
gitRepo.close();
} else {
FileUtils.deleteDirectory(new File(repoName));
throw new internalServerError("Perform git pull before adding any");
}
} catch (GitAPIException | IOException e) {
log.error("Failed to push into git due to {}", ExceptionUtils.getStackTrace(e));
throw new internalServerError(String.format(ExceptionMessage.FAILED_TO_PUSH_INTO_GIT,));
} finally {
FileUtils.deleteQuietly(archiveFolder);
FileUtils.deleteQuietly(xxx);
FileUtils.deleteQuietly(destination);
}
return updateProjectDto;
}
I was using try with resources in clone command and expecting gitRepo object to auto close , but after seeing other posts I understood that we need to close repository also , so I did those changes as well. but still I see my directory is not able to delete.
When I try to delete directory using rm-rf command
tt-798f4978f4-f5pwb:/workspace/pqr/projects/username/workbench$ lsof +D lsof78
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 7 xyz 61r REG 0,44 44988 9572259 lsof78/.git/objects/pack/pack-d4f595d6d76d88356465eac2d60c7ff849255f67.pack
java 7 xyz 65r REG 0,44 226 9572244 lsof78/.git/objects/pack/pack-9c6ee15199d5fb8e65cad42f87428dacd5249d43.pack
This is the error
rm: cannot remove 'lsof78/.git/objects/pack': Directory not empty
I am able to upload multiple files to s3 bucket at once. However there is a mismatch in the file name the one I provided and uploaded file. I am interested in file name as I need to generate cloud front signed url based on that.
File generation code
final String fileName = System.currentTimeMillis() + pictureData.getFileName();
final File file = new File(fileName); //fileName is -> 1594125913522_image1.png
writeByteArrayToFile(img, file);
AWS file upload code
public void uploadMultipleFiles(final List<File> files) {
final TransferManager transferManager = TransferManagerBuilder.standard().withS3Client(amazonS3).build();
try {
final MultipleFileUpload xfer = transferManager.uploadFileList(bucketName, null, new File("."), files);
xfer.waitForCompletion();
} catch (InterruptedException exception) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("InterruptedException occurred=>" + exception);
}
} catch (AmazonServiceException exception) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("AmazonServiceException occurred =>" + exception);
}
throw exception;
}
}
Uploaded file name is 94125913522_image1.png. As you can see first two characters disappeared. What am I missing here. I am not able to figure out. Kindly advice.
private static void writeByteArrayToFile(final byte[] byteArray, final File file) {
try (OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(Paths.get(file.getName())))) {
outputStream.write(byteArray);
} catch (IOException exception) {
throw new FileIllegalStateException("Error while writing image to file", exception);
}
}
The reason of the problem
You lose the first two charecters of the file names because of the third argument of this method:
transferManager.uploadFileList(bucketName, null, new File("."), files);
What happens in this case
So, what is the third argument:
/**
...
* #param directory
* The common parent directory of files to upload. The keys
* of the files in the list of files are constructed relative to
* this directory and the virtualDirectoryKeyPrefix.
...
*/
public MultipleFileUpload uploadFileList(... , File directory, ...){...}
And how will it be used:
...
int startingPosition = directory.getAbsolutePath().length();
if (!(directory.getAbsolutePath().endsWith(File.separator)))
startingPosition++;
...
String key = f.getAbsolutePath().substring(startingPosition)...
Thus, the directory variable is used to define a starting index to trim file paths to get file keys.
When you pass new File(".") as a directory, the parent directory for your files will be {your_path}.
But this is a directory, and you need to work with files inside it. So the common part, retrieved from your directory file, is {your_path}./
That is 2 symbols more than you actually need. And for this reason this method trims the 2 extra characters - an extra shift of two characters when trimming the file path.
The solution
If you only need to work with the current directory, you can pass the current directory as follows:
MultipleFileUpload upload = transferManager.uploadFileList(bucketName, "",
System.getProperty("user.dir"), files);
But if you start working with external sources, it won't work. So you can use this code, which creates one MultipleFileUpload per group of files from one directory.
private final String PATH_SEPARATOR = File.separator;
private String bucketName;
private TransferManager transferManager;
public void uploadMultipleFiles(String prefix, List<File> filesToUpload){
Map<File, List<File>> multipleUploadArguments =
getMultipleUploadArguments(filesToUpload);
for (Map.Entry<File, List<File>> multipleUploadArgument:
multipleUploadArguments.entrySet()){
try{
MultipleFileUpload upload = transferManager.uploadFileList(
bucketName, prefix,
multipleUploadArgument.getKey(),
multipleUploadArgument.getValue()
);
upload.waitForCompletion();
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
private Map<File, List<File>> getMultipleUploadArguments(List<File> filesToUpload){
return filesToUpload.stream()
.collect(Collectors.groupingBy(this::getDirectoryPathForFile));
}
private File getDirectoryPathForFile(File file){
String filePath = file.getAbsolutePath();
String directoryPath = filePath.substring(0, filePath.lastIndexOf(PATH_SEPARATOR));
return new File(directoryPath);
}
I have tried with the following code... Without any luck...
private void updateFile(Drive service, String fileId) {
try {
File file = new File(); /********/
final java.io.File fileToUpdate = new java.io.File("D:/Work Data/Files/pdf.pdf");
FileContent mediaContent = new FileContent("image/pdf", fileToUpdate);
file = service.files().update(fileId, file, mediaContent).execute();
System.out.println(fileId);
} catch (Exception e) {
if (isDebug) {
e.printStackTrace();
}
}
}
also tried with...
private void updateFile(Drive service, String fileId) {
try {
File file = service.files().get(fileId).execute(); /********/
final java.io.File fileToUpdate = new java.io.File("D:/Work Data/Files/pdf.pdf");
FileContent mediaContent = new FileContent("image/pdf", fileToUpdate);
file = service.files().update(fileId, file, mediaContent).execute();
System.out.println(fileId);
} catch (Exception e) {
if (isDebug) {
e.printStackTrace();
}
}
}
With every time i execute the code i get the following stacktrace:
java.lang.IllegalArgumentException
at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument(Preconditions.java:111)
at com.google.api.client.util.Preconditions.checkArgument(Preconditions.java:37)
at com.google.api.client.googleapis.media.MediaHttpUploader.setInitiationRequestMethod(MediaHttpUploader.java:872)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.initializeMediaUpload(AbstractGoogleClientRequest.java:237)
at com.google.api.services.drive.Drive$Files$Update.<init>(Drive.java:3163)
at com.google.api.services.drive.Drive$Files.update(Drive.java:3113)
at com.test.DriveTester.updateFile(DriveTester.java:76)
at com.test.DriveTester.main(DriveTester.java:64)
Can anyone tell what i am doing wrong ? Any sample code for this i.e. updating the content of an already existing file on google drive will be helpful...
For API v3 the solution proposed by Android Enthusiast does not work unfortunately.
The issue is with this bit:
// First retrieve the file from the API.
File file = service.files().get(fileId).execute();
doing this it will create a File object, with it's ID field being set, when executing the update, itt will throw an exception, since the ID meta field is not editable directly.
What you can do is simply create a new file:
File file = new File();
alter the meta you'd like and update file content if required as shown in the example.
then simply update the file as proposed above:
// Send the request to the API.
File updatedFile = service.files().update(fileId, file, mediaContent).execute();
So based a full example would look like this based on Android Enthusiast solution:
private static File updateFile(Drive service, String fileId, String newTitle,
String newDescription, String newMimeType, String newFilename, boolean newRevision) {
try {
// First create a new File.
File file = new File();
// File's new metadata.
file.setTitle(newTitle);
file.setDescription(newDescription);
file.setMimeType(newMimeType);
// File's new content.
java.io.File fileContent = new java.io.File(newFilename);
FileContent mediaContent = new FileContent(newMimeType, fileContent);
// Send the request to the API.
File updatedFile = service.files().update(fileId, file, mediaContent).execute();
return updatedFile;
} catch (IOException e) {
System.out.println("An error occurred: " + e);
return null;
}
}
I can share javascript code for uploading to an already existing file using v3
const url = 'https://www.googleapis.com/upload/drive/v3/files/' + fileId + '?uploadType=media';
if(self.fetch){
var setHeaders = new Headers();
setHeaders.append('Authorization', 'Bearer ' + authToken.access_token);
setHeaders.append('Content-Type', mime);
var setOptions = {
method: 'PATCH',
headers: setHeaders,
body: data
};
fetch(url,setOptions)
.then(response => { if(response.ok){
console.log("save to drive");
}
else{
console.log("Response wast not ok");
}
})
.catch(error => {
console.log("There is an error " + error.message);
});
To update files content, you can use Files:update, this method supports an /upload URI and accepts uploaded media with the following characteristics:
Maximum file size: 5120GB
Accepted Media MIME types: /
This method provides media upload functionality through two separate URIs. For more details, see the document on media upload.
Upload URI, for media upload requests:
PUT https://www.googleapis.com/upload/drive/v2/files/fileId
* Metadata URI, for metadata-only requests:
PUT https://www.googleapis.com/drive/v2/files/fileId
private static File updateFile(Drive service, String fileId, String newTitle,
String newDescription, String newMimeType, String newFilename, boolean newRevision) {
try {
// First retrieve the file from the API.
File file = service.files().get(fileId).execute();
// File's new metadata.
file.setTitle(newTitle);
file.setDescription(newDescription);
file.setMimeType(newMimeType);
// File's new content.
java.io.File fileContent = new java.io.File(newFilename);
FileContent mediaContent = new FileContent(newMimeType, fileContent);
// Send the request to the API.
File updatedFile = service.files().update(fileId, file, mediaContent).execute();
return updatedFile;
} catch (IOException e) {
System.out.println("An error occurred: " + e);
return null;
}
}
You may also check this SO ticket, the ticket discuss the said error.
Source
Unlike the other answers, this solution allows you to upload without having to create a file for the data on the device first.
// Create a File containing any metadata changes.
File metadata = new File().setName(name);
// Convert content to an AbstractInputStreamContent instance.
ByteArrayContent contentStream = ByteArrayContent.fromString("text/plain", content);
// Update the metadata and contents.
mDriveService.files().update(fileId, metadata, contentStream).execute();
Sending the request to Server with the below xml for downloading
<?xml version="1.0" encoding="UTF-8"?>
<ResourceSet xmlns:v01"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<cycleTime>123</cycleTime>
<object>
<sourceUrl>http://10.34894.494/23.png</sourceUrl>
<accessUrl>http://10.126.45.72/cme/23.png</accessUrl>
<objectMetadata>
<headerName>Content-Length</headerName>
<headerName>E-Tag</headerName>
</objectMetadata>
</object>
<object>
<sourceUrl>http://10.84375.72/cme/23.png</sourceUrl>
<accessUrl>http://10.4575.572/cme/logo/23.png</accessUrl>
<objectMetadata>
<headerName>Content-Length</headerName>
<headerName>E-Tag</headerName>
</objectMetadata>
</object>
</ResourceSet>
There are 2 objects and which has same source URL and different Access URl .
My job is to download the image only once because source URL’s are duplicated .
Am iterating through the objects , but how I will know two objects has same source URL to download ?
There are 2 objects and which has same source URL and different Access URl .
My job is to download the image only once because source URL’s are duplicated .
Am iterating through the objects , but how I will know two objects has same source URL to download ?
public void download_resourceset_object_urls_images_to_local() throws Throwable {
List<String> sourceURis = GFDUtils.getSourceOrAccessURLs(xmlPath + xmlFileName, "sourceUrl");
dwInfoList = new HashMap<String, DownloadFileInfo>();
NSAUtils.removeFiles(ConfigLoader.DOWNLOAD_DIR);
boolean flag = HTTPClientFileDownload.downloadFile(sourceURis, ConfigLoader.DOWNLOAD_DIR, dwInfoList);
if (flag == true) {
logger.info("All URL files / images are downloaded successfully....");
} else
throw new GenericException("Files are not available / Failed download ");
}
here am iterating Xml and getting the Source URL to download
public static List<String> getSourceOrAccessURLs(String xmlPath, String urlname) throws IOException {
XStream xs = new XStream();
boolean flag = XMLValidation.validateXMLSchema(xmlPath);
File file = new File(xmlPath);
String xml = FileUtils.readFileToString(file);
if (flag == true) {
List<String> urls = new ArrayList<>();
try {
xs.processAnnotations(Resourceset.class);
Resourceset rs = (Resourceset) xs.fromXML(xml);
List<ResourcesetObject> rsoOject = rs.getResourcesetObject();
for (ResourcesetObject resourcesetObject : rsoOject) {
if (urlname.equals("sourceUrl")) {
urls.add(resourcesetObject.getSourceUrl());
} else {
urls.add(resourcesetObject.getAccessUrl());
}
}
} catch (Exception e) {
e.printStackTrace();
}
return urls;
}
return null;
}
This URL Am passing for downloading.
Please help
Thanks,