Content-Disposition utf8 encoding (golang) - file

It is implementing a file download API
The problem is that the Korean file name is broken
text: "AWS자산.svg"
my code ↓
import (
"github.com/gin-gonic/gin"
"net/url"
)
func FileDownload(c *gin.Context) {
result, infos := fileDownload(c)
if result.Code == 200 {
c.Writer.Header().Set("Content-Type", infos.FileType)
/* infos.FileOgName = AWS자산.svg */
c.FileAttachment(infos.FilePath, infos.FileOgName) // 1 image
c.FileAttachment(infos.FilePath, url.QueryEscape(infos.FileOgName)) // 2 image
} else {
c.JSON(result.Code, result)
}
}
// 3 image
func (c \*Context) FileAttachment(filepath, filename string) {
c.Writer.Header().Set("content-disposition", fmt.Sprintf(attachment; filename\*="UTF-8''%s", filename))
http.ServeFile(c.Writer, c.Request, filepath)
}
I conducted three tests
I sent you a pure file name.
test 1 image
url encoding
test 2 image
Apply by referring to the Internet (filename*="UTF-8''%s")
test 3 image
The problem has not been solved.
I need help from good developers
----------2022-12-09 update-----------
[go gin 1.8.1]
The module update has been completed, but the problem remains.
// FileAttachment writes the specified file into the body stream in an efficient way
// On the client side, the file will typically be downloaded with the given filename
func (c *Context) FileAttachment(filepath, filename string) {
if isASCII(filename) {
c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`)
} else {
c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename))
}
http.ServeFile(c.Writer, c.Request, filepath)
}
test 4 image

Related

How do I save multiple files in a package folder from a SwiftUI Document Based App?

I'm developing a SwiftUI document-based app that contains some easily serializable data plus multiple images. I'd like to save the document as a package (i.e, a folder) with one file containing the easily serialized data and a subfolder containing the images as separate files. My package directory should look something like this:
<UserChosenName.pspkg>/. // directory package containing my document data and images
PhraseSet.dat // regular file with serialized data from snapshot
Images/ // subdirectory for images (populated directly from my app as needed)
Image0.png
Image1.png
....
I've created a FileWrapper subclass that sets up the directory structure and adds the serialized snapshot appropriately but when I run the app in an iOS simulator and click on "+" to create a new document the app runs through the PkgFileWrapper init() and write() without error but returns to the browser window without apparently creating anything. I have declared that the Exported and Imported Type Identifiers conform to "com.apple.package". Can anyone suggest a way to get this working?
The PkgFileWrapper class looks like this:
class PkgFileWrapper: FileWrapper {
var snapshot: Data
init(withSnapshot: Data) {
self.snapshot = withSnapshot
let sWrapper = FileWrapper(regularFileWithContents: snapshot)
let dWrapper = FileWrapper(directoryWithFileWrappers: [:])
super.init(directoryWithFileWrappers: ["PhraseSet.dat" : sWrapper,
"Images" : dWrapper ])
// NOTE: Writing of images is done outside
// of the ReferenceFileDocument functionality.
}
override func write(to: URL,
options: FileWrapper.WritingOptions,
originalContentsURL: URL?) throws {
try super.write(to: to, options: options,
originalContentsURL: originalContentsURL)
}
required init?(coder inCoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The solution is to not override PkgFileWrapper.write(...). If the directory structure is set up correctly in the init(...) then the files and directories will be created automatically. The overridden write(...) function above has now been corrected.
If you want to write an image to the Images subdirectory, you could do something like the following:
func addImage(image: UIImage, name: String) {
let imageData = image.pngData()!
imageDirWrapper.addRegularFile(withContents: imageData,
preferredFilename: name)
}
The value of imageDirWrapper is the directory wrapper corresponding to the directory that holds your images, as created in PkgFileWrapper.init() above. A key concept you need to keep in mind here is that the "write" function will get called automatically at the appropriate time - you don't explicitly write out your image data. The ReferenceFileDocument class will arrange for that and will also arrange for your app to be passed the appropriate URL for setting up your file wrappers.
The imageDirWrapper variable is set in the required init(...) for the ReferenceFileDocument protocol:
required init(configuration: ReadConfiguration) throws {
phraseSet = PhraseSet()
if configuration.file.isDirectory {
if let subdir = configuration.file.fileWrappers {
// first load in the phraseSet
for (name, wrapper) in subdir {
if name == PkgFileWrapper.phraseSetFileName {
if let data = wrapper.regularFileContents {
phraseSet = try PhraseSet(json: data)
}
}
}
// next load in the images and put them into the phrases.
for (name, wrapper) in subdir {
if name == PkgFileWrapper.imageDirectoryName {
if let imageDir = wrapper.fileWrappers {
imageDirWrapper = wrapper
for (iName, iWrapper) in imageDir {
print("image file: \(iName)")
if let d = iWrapper.regularFileContents {
for p in phraseSet.phrases {
if p.imageName == iName {
// TBD: downsample
var uiD = ImageData(data: d)
if doDownSample {
uiD.uiimageData = downsample(data: d,
to: imageSize)
} else {
_ = uiD.getUIImage()
}
images[iName] = uiD
}
}
}
}
}
}
}
}
} else {
throw CocoaError(.fileReadCorruptFile)
}
You can see here how imageDirWrapper is set by looking through the passed-in directory's subdirectories for the image directory name. Also some bonus code: it first looks through the passed-in directory for the data file and loads it in; then it looks for the image directory and processes it.

Dart - HTTPClient download file to string

In the Flutter/Dart app that I am currently working on need to download large files from my servers. However, instead of storing the file in local storage what I need to do is to parse its contents and consume it one-off. I thought the best way to accomplish this was by implementing my own StreamConsumer and overriding the relvant methods. Here is what I have done thus far
import 'dart:io';
import 'dart:async';
class Accumulator extends StreamConsumer<List<int>>
{
String text = '';
#override
Future<void> addStream(Stream<List<int>> s) async
{
print('Adding');
//print(s.length);
return;
}
#override
Future<dynamic> close() async
{
print('closed');
return Future.value(text);
}
}
Future<String> fileFetch() async
{
String url = 'https://file.io/bse4moAYc7gW';
final HttpClientRequest request = await HttpClient().getUrl(Uri.parse(url));
final HttpClientResponse response = await request.close();
return await response.pipe(Accumulator());
}
Future<void> simpleFetch() async
{
String url = 'https://file.io/bse4moAYc7gW';
final HttpClientRequest request = await HttpClient().getUrl(Uri.parse(url));
final HttpClientResponse response = await request.close();
await response.pipe(File('sample.txt').openWrite());
print('Simple done!!');
}
void main() async
{
print('Starting');
await simpleFetch();
String text = await fileFetch();
print('Finished! $text');
}
When I run this in VSCode here is the output I get
Starting
Simple done!! //the contents of the file at https://file.io/bse4moAYc7gW are duly saved in the file
sample.txt
Adding //clearly addStream is being called
Instance of 'Future<int>' //I had expected to see the length of the available data here
closed //close is clearly being called BUT
Finished! //back in main()
My understanding of the underlying issues here is still rather limited. My expectation
I had thought that I would use addStream to accumulate the contents being downloaded until
There is nothing more to download at which point close would be called and the program would display exited
Why is addStream showing instance of... rather than the length of available content?
Although the VSCode debug console does display exited this happens several seconds after closed is displayed. I thought this might be an issue with having to call super.close() but not so. What am I doing wrong here?
I was going to delete this question but decided to leave it here with an answer for the benefit of anyone else trying to do something similar.
The key point to note is that the call to Accumulator.addStream does just that - it furnishes a stream to be listened to, no actual data to be read. What you do next is this
void whenData(List<int> data)
{
//you will typically get a sequence of one or more bytes here.
for(int value in data)
{
//accumulate the incoming data here
}
return;
}
function void whenDone()
{
//now that you have all the file data *accumulated* do what you like with it
}
#override
Future<void> addStream(Stream<List<int>> s) async
{
s.listen(whenData,onDone:whenDone);
//you can optionally ahandler for `onError`
}

Reading & writing data to a .txt file using vscode extension api

So I am new to this vscode extension api. I have this functionality where I need to take input from the user when they click on certain line and then get the 1). input value, line number and file name and 2). store it to a text file.
I am done with the first part, I am getting the data everything. Now I have to just write it to the file and if there is data already, new data should be appended not overwritten.
I have tried using fs.writeFileSync(filePath, data) and readFileSync but nothing, I do not know if I am doing it correctly. If someone can point me in the right direction I am just blank at this stage?
Any help would be appreciated, Thanks in advance.
The FS node module works fine in an extension. I use it all the time for file work in my extension. Here's a helper function to export something to a file with error handling:
/**
* Asks the user for a file to store the given data in. Checks if the file already exists and ask for permission to
* overwrite it, if so. Also copies a number extra files to the target folder.
*
* #param fileName A default file name the user can change, if wanted.
* #param filter The file type filter as used in showSaveDialog.
* #param data The data to write.
* #param extraFiles Files to copy to the target folder (e.g. css).
*/
public static exportDataWithConfirmation(fileName: string, filters: { [name: string]: string[] }, data: string,
extraFiles: string[]): void {
void window.showSaveDialog({
defaultUri: Uri.file(fileName),
filters,
}).then((uri: Uri | undefined) => {
if (uri) {
const value = uri.fsPath;
fs.writeFile(value, data, (error) => {
if (error) {
void window.showErrorMessage("Could not write to file: " + value + ": " + error.message);
} else {
this.copyFilesIfNewer(extraFiles, path.dirname(value));
void window.showInformationMessage("Diagram successfully written to file '" + value + "'.");
}
});
}
});
}
And here an example where I read a file without user intervention:
this.configurationDone.wait(1000).then(() => {
...
try {
const testInput = fs.readFileSync(args.input, { encoding: "utf8" });
...
} catch (e) {
...
}
...
});

how to make an array of urls from a folder (swift, audio)

I´m looking for a way to make an array of urls from the contents of a folder containing soundfiles so that i can call them up with AVAudioplayer later.
I use a stepper and 3 variables,
the first one is called nmbTracks to define the number of playable soundfiles, and holds the steppers maxvalue
the second is called currentActiveTrack and defines which file the player should be playing.
the 3rd one is called audioURL and is used to feed the player aswell as retrieving the name of of the file which gets outputed to a label.
the user can then step through the soundfiles with the stepper.
so far I got everything working with some files that i have but I can´t figure out how to make an array of urls nor how to get urls from the contents of a folder, next step is to let the user import their own files into that folder.
any help would be greatly appreciated, I´m sure there is an easier way to do this aswell
I have a couple of options. The first one returns an array of URLs and if there is an error fetching the folder returns an empty array.
func getFolderContentsURLs(_ folderPath: String) -> [URL] {
let fm = FileManager()
guard let contents = try? fm.contentsOfDirectory(atPath: folderPath) else { return [] }
return contents.compactMap { URL.init(fileURLWithPath: $0) }
}
You can display the result like this:
let songsURLs = getFolderContentsURLs("/")
songsURLs.forEach {
print($0.absoluteString)
}
The second option return an optional array of URLs, on error returns nil
func getFolderContentsURLsOrNil(_ folderPath: String) -> [URL]? {
let fm = FileManager()
guard let contents = try? fm.contentsOfDirectory(atPath: folderPath) else { return nil }
return contents.compactMap { URL.init(fileURLWithPath: $0) }
}
To go through the results you can do it like this:
if let songsURLs2 = getFolderContentsURLsOrNil("NotExistingPath") {
songsURLs2.forEach {
print($0.absoluteString)
}
} else {
print("Unable to fetch contents")
}
Responding to #user12184258 comment about returning only audio files you can apply a filter after getting the folder contents. The filter can check each file using UTTypeConformsTo from MobileCoreServices
let contentsFolder = getFolderContentsURLs("/path/to/folder")
let audioFiles = contentsFolder
.filter { path in
// Try to create uniform type identifier using file's extension
guard let uti =
UTTypeCreatePreferredIdentifierForTag(
kUTTagClassFilenameExtension,
path.pathExtension as CFString, nil) else { return false }
// Checks conformance of UTI with kUTTypeAudio (abstract type for audio)
return UTTypeConformsTo((uti.takeRetainedValue()), kUTTypeAudio)
}
I found this method here. Also Apple has a very useful System-Declared Uniform Type Identifiers you can check, if you want only mp3 files you can use kUTTypeMP3.

How to read plain text file in kotlin?

There may be various way to read plain text file in kotlin.
I want know what are the possible ways and how I can use them.
1. Using BufferedReader
import java.io.File
import java.io.BufferedReader
fun main(args: Array<String>) {
val bufferedReader: BufferedReader = File("example.txt").bufferedReader()
val inputString = bufferedReader.use { it.readText() }
println(inputString)
}
2. Using InputStream
Read By Line
import java.io.File
import java.io.InputStream
fun main(args: Array<String>) {
val inputStream: InputStream = File("example.txt").inputStream()
val lineList = mutableListOf<String>()
inputStream.bufferedReader().forEachLine { lineList.add(it) }
lineList.forEach{println("> " + it)}
}
Read All Lines
import java.io.File
import java.io.InputStream
fun main(args: Array<String>) {
val inputStream: InputStream = File("example.txt").inputStream()
val inputString = inputStream.bufferedReader().use { it.readText() }
println(inputString)
}
3. Use File directly
import java.io.File
import java.io.BufferedReader
fun main(args: Array<String>) {
val lineList = mutableListOf<String>()
File("example.txt").useLines { lines -> lines.forEach { lineList.add(it) }}
lineList.forEach { println("> " + it) }
}
I think the simplest way to code is using kotlin.text and java.io.File
import java.io.File
fun main(args: Array<String>) {
val text = File("sample.txt").readText()
println(text)
}
The answers above here are all based on Kotlin Java. Here is a Kotlin Native way to read text files:
val bufferLength = 64 * 1024
val buffer = allocArray<ByteVar>(bufferLength)
for (i in 1..count) {
val nextLine = fgets(buffer, bufferLength, file)?.toKString()
if (nextLine == null || nextLine.isEmpty()) break
val records = parseLine(nextLine, ',')
val key = records[column]
val current = keyValue[key] ?: 0
keyValue[key] = current + 1
}
fun parseLine(line: String, separator: Char) : List<String> {
val result = mutableListOf<String>()
val builder = StringBuilder()
var quotes = 0
for (ch in line) {
when {
ch == '\"' -> {
quotes++
builder.append(ch)
}
(ch == '\n') || (ch == '\r') -> {}
(ch == separator) && (quotes % 2 == 0) -> {
result.add(builder.toString())
builder.setLength(0)
}
else -> builder.append(ch)
}
}
return result
}
See: https://github.com/JetBrains/kotlin-native/blob/master/samples/csvparser/src/csvParserMain/kotlin/CsvParser.kt
Anisuzzaman's answer lists several possibilities.
The main differences between them are in whether the file is read into memory as a single String, read into memory and split into lines, or read line-by-line.
Obviously, reading the entire file into memory in one go can take a lot more memory, so that's something to avoid unless it's really necessary.  (Text files can get arbitrarily big!)  So processing line-by-line with BufferedReader.useLines() is often a good approach.
The remaining differences are mostly historical.  Very early versions of Java used InputStream &c which didn't properly distinguish between characters and bytes; Reader &c were added to correct that.  Java 8 added ways to read line-by-line more efficiently using streams (e.g. Files.lines()).  And more recently, Kotlin has added its own extension functions (e.g. BufferedReader.useLines()) which make it even simpler.
To read a text file, it must first be created. In Android Studio, you would create the text file like this:
1) Select "Project" from the top of the vertical toolbar to open the project "tool window"
2) From the drop-down menu at the top of the "tool window", select "Android"
3) Right-click on "App" and select "New"
then -> "Folder" (the one with the green Android icon beside it)
then -> "Assets Folder"
4) Right-click on the "assets" folder after it appears in the "tool window"
5) Select "New" -> "File"
6) Name the file, and included the extension ".txt" if it is text file, or ".html" if it is for WebView
7) Edit the file or cut and paste text into it. The file will now display under the "Project" files in the "tool window" and you will be able to double-click it to edit it at any time.
TO ACCESS THIS FILE, use a prefix of "application.assets." followed by someFunction(fileName). For example (in Kotlin):
val fileName = "townNames.txt"
val inputString = application.assets.open(fileName).bufferedReader().use { it.readText() }
val townList: List<String> = inputString.split("\n")
how to apply Documents path on that:
fun main(args: Array<String>) {
val inputStream: InputStream = File("example.txt").inputStream()
val inputString = inputStream.bufferedReader().use { it.readText() }
println(inputString)
}

Resources