Перейти к содержимому

Как сохранить txt файл в бд spring

  • автор:

Как сохранить txt файл в бд spring

Хотя с помощью ранее рассмотренных классов можно записывать текст в файлы, однако они предназначены прежде всего для работы с бинарными потоками данных, и их возможностей для полноценной работы с текстовыми файлами недостаточно. И для этой цели служат совсем другие классы, которые являются наследниками абстрактных классов Reader и Writer .

Запись файлов. Класс FileWriter

Класс FileWriter является производным от класса Writer. Он используется для записи текстовых файлов.

Чтобы создать объект FileWriter, можно использовать один из следующих конструкторов:

FileWriter(File file) FileWriter(File file, boolean append) FileWriter(FileDescriptor fd) FileWriter(String fileName) FileWriter(String fileName, boolean append)

Так, в конструктор передается либо путь к файлу в виде строки, либо объект File, который ссылается на конкретный текстовый файл. Параметр append указывает, должны ли данные дозаписываться в конец файла (если параметр равен true), либо файл должен перезаписываться.

Запишем в файл какой-нибудь текст:

import java.io.*; public class Program < public static void main(String[] args) < try(FileWriter writer = new FileWriter("notes3.txt", false)) < // запись всей строки String text = "Hello Gold!"; writer.write(text); // запись по символам writer.append('\n'); writer.append('E'); writer.flush(); >catch(IOException ex) < System.out.println(ex.getMessage()); >> >

В конструкторе использовался параметр append со значением false — то есть файл будет перезаписываться. Затем с помощью методов, определенных в базовом классе Writer производится запись данных.

Чтение файлов. Класс FileReader

Класс FileReader наследуется от абстрактного класса Reader и предоставляет функциональность для чтения текстовых файлов.

Для создания объекта FileReader мы можем использовать один из его конструкторов:

FileReader(String fileName) FileReader(File file) FileReader(FileDescriptor fd)

А используя методы, определенные в базом классе Reader, произвести чтение файла:

import java.io.*; public class Program < public static void main(String[] args) < try(FileReader reader = new FileReader("notes3.txt")) < // читаем посимвольно int c; while((c=reader.read())!=-1)< System.out.print((char)c); >> catch(IOException ex) < System.out.println(ex.getMessage()); >> >

Также мы можем считывать в промежуточный буфер из массива символов:

import java.io.*; import java.util.Arrays; public class Program < public static void main(String[] args) < try(FileReader reader = new FileReader("notes3.txt")) < char[] buf = new char[256]; int c; while((c = reader.read(buf))>0) < if(c < 256)< buf = Arrays.copyOf(buf, c); >System.out.print(buf); > > catch(IOException ex) < System.out.println(ex.getMessage()); >> >

В данном случае считываем последовательно символы из файла в массив из 256 символов, пока не дойдем до конца файла в этом случае метод read возвратит число -1.

Поскольку считанная порция файла может быть меньше 256 символов (например, в файле всего 73 символа), и если количество считанных данных меньше размера буфера (256), то выполняем копирование массива с помощью метода Arrays.copy. То есть фактически обрезаем массив buf, оставляя в нем только те символы, которые считаны из файла.

База данных в текстовом файле

Создаю простое приложение которое должно хранить данные пользователя в текстовом файле (один для всех пользователей), авторизация также должна проходить на основе этого файла. Подскажите пожалуйста как это правильно организовать? Может у кого есть пример такого решения. Библиотеки использовать нельзя, также как и xml и json.

Отслеживать
задан 22 янв 2018 в 12:24
Андрей Оробец Андрей Оробец
3 3 3 бронзовых знака

Реализуйте на коленке csv, в случае если не требуется использование экранируемых символов (т.е. приложение запрещает использование запятых и прочего) это тривиально

22 янв 2018 в 12:28

Та в java даже готовый Properties есть, который что то на вроде ini строит. Даже на коленке не надо ничего писать. mkyong.com/java/java-properties-file-examples

22 янв 2018 в 12:45

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

у меня есть пример но не знаю может быть полезно для вас или нет ! И так! Во первых создайте папку и внутри создайте FILE в формате текст это будет служить для хранилище данных.Нужно создать папку с именем model и внутри создать класс который будет хранить переменние например String name,String surname и.т.д . необходимо чтобы этот класс был implemets на Serializable в этом классе нужно ovveride-ить Getter Setter EqualsAndHashCode Constructor defaultConstructor и в этом классе всё. потом нужно создать папку с именем util внутри создать класс с иминем SerializeUtil и объявлять следующее
public static final String USER-FILE-PATH = «И ЗДЕСТЬ ДАТЬ РЕЛАТИВ ПУТЬ В ЭТОМУ ФАЙЛУ ПРИМЕР -src\mailService\data\users»; И ПОД ЭТОМУ ПИШЕМ СЛЕДУЮЩИЙ ЧТОБЫ ПОТОМ ЗВАТЬ ЭТОТ МЕТОД ЧТОБЫ КИНУТЬ USER А В ФАЙЛ

public static void serializeUser(Map userMap) throws IOException

И ПОД ЭТОМУ КОДУ ПИШЕМ СЛЕДУЮЩИЙ КОТОРЫЙ БУДЕТ ПОКАЗАТЬ ВСЕХ USER ОВ В КОНСОЛЬ потом этот метод можно звать когда хотите увидеть всех user ов но извините я забыл логику который нужно было писать и звать этот метод

public static Map deserializeUser() throws IOException, ClassNotFoundException < ObjectInputStream objectInputStream = new ObjectInputStream( new FileInputStream(USER_FILE_PATH)); return (Map) objectInputStream.readObject(); > 

ТЕПЕРЬ СОЗДАЕМ ПАПКУ С ИМЕНЕМ storage И ВНУТРИ СОЗДАЕМ КЛАСС UserStorage И ВНУТРИ ПИШЕМ СЛЕДУЮЩИЙ КОД ЧТОБЫ КИНУТЬ USER А В ФАЙЛ

private Map users = new HashMap<>(); public void add(User user) < users.put(user.getEmail(), user); try < SerializeUtil.serializeUser(users); >catch (IOException e) < System.out.println(e); >> 

И В ГЛАВНЫЙ КЛАСС КОТОРЫЙ Я НАЗЫВАЛ TEST НУЖНО ЗВАТЬ ЭТИ МЕТОДЫ НАПРИМЕР ЭТОТ МЕТОД ДЛЯ РЕГИСТРАЦИИ

 `private static void register() < System.out.println("Please input name,surname,email,password"); String userDataStr = SCANNER.nextLine(); String[] userData = userDataStr.split(","); User user = new User(); user.setName(userData[0]); user.setSurname(userData[1]); user.setEmail(userData[2]); user.setPassword(userData[3]); USER_STORAGE.add(user); System.out.println("User was successfully added"); >>` 

И когда регистрировали все данные буду падать в файл

ну и скажите от куда у меня такой странный русский язык . я не русский ))))

#4 — Запись и чтение данных из файлов (Java io)

#4 - Запись и чтение данных из файлов (Java io)

Работа с файлами это важная часть многих языков программирования. В уроке мы научимся работать с файлами. Мы изучим добавление и чтение информации из файлов.

Видеоурок

Многие языки программирования предоставляют классы для работы с файлами и директориями проекта. Язык Java обладает множеством классов для записи и чтения данных из файлов.

Работа с файлами

При работе с файлами всегда необходимо помнить две вещи:

  1. Перед началом работы с файлом его необходимо открыть;
  2. После завершения работы с файлом его необходимо закрыть.

Если файл не открыт или же неверно открыт, то вы не можете полноценно работать с его содержимым.

С закрытием все проще, но и коварнее. Если вы не закроете файл, то программа будет работать верно, тем не менее, чем больше будет открытых файлов, тем больше программа будет перегружена и в какой-то момент она просто зависнет или выключиться.

Исключения и файлы

Поскольку не всегда известно будет ли файл в проекте или на компьютере пользователя, то всегда лучше открывать файлы за счёт использования исключений. Выполняйте открытие файлов в блоке try catch и тем самым вы обезопасите себя от любых непредвиденных обстоятельств.

Запись данных в файл

При записи данных в файл его изначально необходимо открыть. Для этого в языке Java используется класс «File»:

File file = new File("fileName.txt");

После открытия файла вы можете записать в него данные за счёт класса «PrintWriter»:

// Указываем файл для записи // В качестве объекта передаем открытый файл на основе класса File PrintWriter pw = new PrintWriter(file); // Помещаем текст внутрь файла pw.println("Working proccess"); 

В конце файл необходимо закрыть:

pw.close();
Чтение данных из файла

Для чтения данных файл необходимо также изначально открыть и в конце закрыть. Чтобы прочесть содержимое файла используется класс BufferedReader :

// Открываем файл для чтения // В качестве объекта передаем открытый файл на основе класса FileReader BufferedReader br = new BufferedReader(file); // Считываем данные while((String line = br.readLine()) != null) < // Выводим каждую отдельную строку в консоль System.out.println(line); >
Весь код будет доступен после подписки на проект!

Сохранение файлов в приложение и данных о них на БД

Java-университет

Сохранение файлов в приложение и данных о них на БД - 1Давай представим, что ты работаешь над своим веб-приложением. В своих статьях я рассматриваю отдельные кусочки этой мозаики, как например:

  • Интеграционное тестирование БД с помощью MariaDB для подмены MySql
  • Реализация мультиязычности приложения

Чем эти темы полезны? А тем, что эти примеры очень близки к работе над реальными проектами, и прощупать эти темы будет ну очень полезно для тебя. Сегодня мы возьмём следующий кусочек данной мозаики — работу с файлами, так как в наше время уже и не встретить сайта, который не взаимодействует с ними (например всякие там веб-шопы, соцсети и так далее). Обзор будет проводиться на примере методов upload/download/delete , сохранять мы будем в папку (в resource) в нашем приложении, чтобы не усложнять. Сохранение файлов в приложение и данных о них на БД - 2Задумка состоит в том, что мы будем сохранять, помимо самого файла в наше так называемое file storage (хранилище), сущность с информацией о нашем файле (size, name и т.д.) в нашу БД — предварительно созданную таблицу. То есть при загрузке файла нам эта сущность очень даже пригодится, ну и при delete о ней нельзя никоим образом забывать. Пробежимся взглядом по этой таблице: Сохранение файлов в приложение и данных о них на БД - 3И давайте уже как взрослые поставим на id AUTO_INCREMENT, для автогенерирования индефикатора на уровне БД. Для начала взглянем на нашу структуру: Сохранение файлов в приложение и данных о них на БД - 4Сущность под продемонстрированную выше таблицу:

 @Builder(toBuilder = true) @Getter @ToString public class FileInfo

Upload

Смотрим контроллер:

 @RestController @RequestMapping("/file") @RequiredArgsConstructor public class FileController < private final FileService fileService; @PostMapping public ResponseEntityupload(@RequestParam MultipartFile attachment) < try < return new ResponseEntity<>(fileService.upload(attachment), HttpStatus.CREATED); > catch (IOException e) < return new ResponseEntity<>(HttpStatus.BAD_REQUEST); > > 

Из интересного: 9 — Принимаем файл в виде MultipartFile . Можно принимать и в виде массива байтов, но этот вариант мне нравится больше, так как мы с MultipartFile можем вытягивать различные свойства переданного файла. 10 — 14 — оборачиваем наши действия в try catch , чтобы если на более низком уровне возникнет исключение, мы его пробросили выше и отправили 400 ошибку ответом. Далее — уровень сервиса:

 public interface FileService < FileInfo upload(MultipartFile resource) throws IOException; 

Смотрим реализацию:

 @Service @RequiredArgsConstructor public class FileServiceImpl implements FileService < private final FileDAO fileDAO; private final FileManager fileManager; @Transactional(rollbackFor = ) @Override public FileInfo upload(MultipartFile resource) throws IOException

8 — в случае падения IOException, все наши сохранения в БД откатятся. 11 — генерируем ключ, который будет уникальным для файла, когда он будет соохранен (даже если будут сейвиться два файла с одинаковыми именами, путаницы не возникнет). 12 — строим сущность для сохранения в БД. 17 — загоняем сущность с инфой в БД. 18 — сохраняем файл с за хешированным именем. 20 — возвращаем созданую сущность FileInfo , но со сгенерированным id в БД (об этом речь пойдёт чуть ниже) и датой создания. Метод генерации ключа к файлу:

 private String generateKey(String name)

Здесь мы хешируем имя + дата создания, что и обеспечит нам уникальность. Интерфейс dao слоя:

 public interface FileDAO < FileInfo create(FileInfo file); 

Его имплементация:

 @Repository @RequiredArgsConstructor public class FileDAOImpl implements FileDAO < private static final String CREATE_FILE = "INSERT INTO files_info(file_name, file_size, file_key, upload_date) VALUES (?, ?, ?, ?)"; private final JdbcTemplate jdbcTemplate; @Override public FileInfo create(final FileInfo file) < LocalDate uploadDate = LocalDate.now(); GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(x ->< PreparedStatement preparedStatement = x.prepareStatement(CREATE_FILE, Statement.RETURN_GENERATED_KEYS); preparedStatement.setString(1, file.getName()); preparedStatement.setLong(2, file.getSize()); preparedStatement.setString(3, file.getKey()); preparedStatement.setDate(4, Date.valueOf(uploadDate)); return preparedStatement; >, keyHolder); return file.toBuilder() .id(keyHolder.getKey().longValue()) .uploadDate(uploadDate) .build(); > 

11 — создаём дату которую и сохраним. 12 - 21 — сохраняем сущность, но более сложным путем, с явным созданием объекта PreparedStatement , чтобы можно было вытащить сгенерированный id (он его вытягивает не отдельным запросом, а в виде ответных метаданных). 22 - 26 — достраиваем нашу многострадальную сущность и отдаем наверх (на самом деле он его не достраивает, а создаёт новый объект, заполняя переданные поля и копируя остальные с изначального). Давайте посмотрим, как будут сохраняться наши файлы в FileManager :

 public void upload(byte[] resource, String keyName) throws IOException < Path path = Paths.get(DIRECTORY_PATH, keyName); Path file = Files.createFile(path); FileOutputStream stream = null; try < stream = new FileOutputStream(file.toString()); stream.write(resource); >finally < stream.close(); >> 

Сохранение файлов в приложение и данных о них на БД - 5

1 — принимаем файл в виде массива байтов и отдельно имя, под которым он будет сохранен (наш сгенерированный ключ). 2 - 3 — создаем путь (а в пути прописываем путь плюс наш ключ) и файл по нему. 6 - 7 — создаем поток и пишем туда наши байты (и оборачиваем это все добро в try-finally чтобы быть уверенными, что поток точно закроется). Тем не менее, многие из методов могут нам выкинуть IOException. В таком случае, благодаря прописанной в шапке метода проброске, мы прокинем его в контроллер и отдадим 400 статус. Давайте протестируем все это дело в Postman: Как видим, все отлично, ответ 201, ответный JSON пришел в виде нашей сохраняемой сущности в БД, и если заглянем в наше хранилище: БД: увидим, что у нас появилось новое значение. (=*;*=)

Download

Controller:

 @GetMapping(path = "/", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) public ResponseEntity download(@PathVariable("id") Long id) < try < FileInfo foundFile = fileService.findById(id); Resource resource = fileService.download(foundFile.getKey()); return ResponseEntity.ok() .header("Content-Disposition", "attachment; filename lang-java line-numbers"> Resource download(String key) throws IOException; FileInfo findById(Long fileId); 

Реализация:

 @Override public Resource download(String key) throws IOException < return fileManager.download(key); >@Transactional(readOnly = true) @Override public FileInfo findById(Long fileId)

Тут особо интересного ничего нет: метод поиска сущности по id и загрузка файла, разве что 46 — помечаем, что транзакция у нас для чтения. Уровень dao:

 FileInfo findById(Long fileId); 

Имплементация:

 private static final String FIND_FILE_BY_ID = "SELECT id, file_name, file_size, file_key, upload_date FROM files_info WHERE FileInfo findById(Long fileId) < return jdbcTemplate.queryForObject(FIND_FILE_BY_ID, rowMapper(), fileId); >private RowMapper rowMapper() < return (rs, rowNum) ->FileInfo.builder() .id(rs.getLong("id")) .name(rs.getString("file_name")) .size(rs.getLong("file_size")) .key(rs.getString("file_key")) .uploadDate(rs.getObject("upload_date", LocalDate.class)) .build(); > 

4 — поиск по id c использованием jdbcTemplate и RowMapper . 8 - 15 — реализация RowMapper для нашего конкретного случая, для сопоставления данных из БД и полей модели. Идем в FileManager и смотрим, как загружается наш файл:

 public Resource download(String key) throws IOException < Path path = Paths.get(DIRECTORY_PATH + key); Resource resource = new UrlResource(path.toUri()); if (resource.exists() || resource.isReadable()) < return resource; >else < throw new IOException(); >> 

Сохранение файлов в приложение и данных о них на БД - 7

Возвращаем файл в виде объекта Resource , а искать будем по ключу. 3 — создаем Resource по пути + ключ. 4 - 8 — проверяем, что файл по заданному пути не пуст и читаем. Если всё ОК, возвращаем его, а если нет, прокидываем IOException наверх. Проверяем наш метод в Postman: Как видим, он отработал на ОК))

Delete

 @DeleteMapping(value = "/") public ResponseEntity delete(@PathVariable("id") Long id) < try < fileService.delete(id); return new ResponseEntity<>(HttpStatus.OK); > catch (IOException e) < return new ResponseEntity<>(HttpStatus.NOT_FOUND); > > 

Тут ничего особенного: также возвращаем 404 в случае неудачи с помощью try-catch . Интерфейс сервиса:

 void delete(Long fileId) throws IOException; 

Implementation:

 @Transactional(rollbackFor = ) @Override public void delete(Long fileId) throws IOException

1 — также откат изменения данных (удаления) при падении IOException. 5 — удаляем информацию о файле из БД. 6 — удаляем сам файл из нашего “хранилища”. Интерфейс dao:

 void delete(Long fileId); 

Реализация:

 private static final String DELETE_FILE_BY_ID = "DELETE FROM files_info WHERE void delete(Long fileId)

Ничего такого — просто delete. Удаление самого файла:

 public void delete(String key) throws IOException < Path path = Paths.get(DIRECTORY_PATH + key); Files.delete(path); >> 

Юзаем в Postman: Сохранение файлов в приложение и данных о них на БД - 8Смотрим в хранилище: Сохранение файлов в приложение и данных о них на БД - 9Пусто 🙂 Теперь в БД: Сохранение файлов в приложение и данных о них на БД - 10Видим, что все good))

Test

Давайте попробуем написать тест под наш FileManager . Для начала взглянем на структуру тестовой части: mockFile.txt — это файл, с помощью которого мы будем тестить наши операции с file storage. testFileStorage будет заменой нашего хранилища. FileManagerTest :

 public class FileManagerTest < private static MultipartFile multipartFile; private static FileManager manager; private static FileInfo file; @BeforeClass public static void prepareTestData() throws IOException < file = FileInfo.builder() .id(9L) .name("mockFile.txt") .key("mockFile.txt") .size(38975L) .uploadDate(LocalDate.now()) .build(); multipartFile = new MockMultipartFile("mockFile", "mockFile.txt", "txt", new FileInputStream("src/test/resources/mockFile.txt")); manager = new FileManager(); >

Здесь мы видим задание тестовых данных. Тест сохранения файла:

 @Test public void uploadTest() throws IOException < ReflectionTestUtils.setField(manager, "DIRECTORY_PATH", "src/test/resources/testFileStorage/"); manager.upload(multipartFile.getBytes(), "mockFile.txt"); Path checkFile = Paths.get("src/test/resources/testFileStorage/mockFile.txt"); assertThat(Files.exists(checkFile)).isTrue(); assertThat(Files.isRegularFile(checkFile)).isTrue(); assertThat(Files.size(checkFile)).isEqualTo(multipartFile.getSize()); Files.delete(checkFile); >

3 — с помощью тестовой рефлексии меняем нашу константу в сервисе для задания пути сохранения файла. 5 — вызываем проверяемый метод. 7 - 10 — проверяем правильность исполнения сохранения. 11 — удаляем сохраненный файл (мы не должны оставить никаких следов).

 @Test public void downloadTest() throws IOException < ReflectionTestUtils.setField(manager, "DIRECTORY_PATH", "src/test/resources/"); Resource resource = manager.download(file.getKey()); assertThat(resource.isFile()).isTrue(); assertThat(resource.getFilename()).isEqualTo(file.getName()); assertThat(resource.exists()).isTrue(); >

Тест загрузки файла: 3 — опять же, меняем путь для нашего FileManager . 5 — юзаем проверяемый метод. 7 - 9 — проверяем результат исполнения. Тест удаления файла:

 @Test public void deleteTest() throws IOException < Path checkFile = Paths.get("src/test/resources/testFileStorage/mockFile.txt"); Files.createFile(checkFile); assertThat(Files.exists(checkFile)).isTrue(); assertThat(Files.isRegularFile(checkFile)).isTrue(); ReflectionTestUtils.setField(manager, "DIRECTORY_PATH", "src/test/resources/testFileStorage/"); manager.delete(file.getKey()); assertThat(Files.notExists(checkFile)).isTrue(); >

9 - 3 - 4 — задаем путь и создаем файл. 5 - 6 — проверяем его существование. 9 — используем проверяемый метод. 77 — проверяем, что обьекта уже нет. И смотрим, что там у нас по зависимостям:

   org.springframework.boot spring-boot-starter-data-jdbc  org.springframework.boot spring-boot-starter-web  org.springframework.boot spring-boot-starter-test test  org.junit.vintage junit-vintage-engine    org.projectlombok lombok 1.18.10 provided  mysql mysql-connector-java 8.0.18  commons-codec commons-codec 1.9  junit junit 4.13-rc-2 test   

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *